diff --git a/app/AGENTS.md b/app/AGENTS.md index 45254675e..34cf3f02a 100644 --- a/app/AGENTS.md +++ b/app/AGENTS.md @@ -28,7 +28,7 @@ Key structure: ## Important Development Notes - **Naming conventions** - Constants, enum members, and `static readonly` fields use `UPPER_SNAKE_CASE` such as `MY_CONSTANT`. -- **Extension members** - Declare extension methods in an `extension` block of their static class, one block per receiver, never with a `this` parameter: MWAIS0016 refuses the classic form. The `` of the receiver, and of a generic block its ``, belongs on the block, not on its members. +- **Extension members** - Declare extension methods in an `extension` block of their static class, one block per receiver, never with a `this` parameter: MWAIS0016 refuses the classic form. The `` of the receiver, and of a generic block its ``, belongs on the block, not on its members. A member which only looks something up about its receiver, such as a name, an icon, a flag, a prompt, or an address, is an extension property, named without `Get` or `To`: `format.FileExtension`, `host.IsChatSupported`. It stays a method when it takes parameters, builds something new such as a list or a model profile, parses, scans a collection, or converts into another type, as `GetModelProfile`, `CompactCount`, and `ToSources` do. Check first that the receiver has no instance member of the same name, which would hide the extension. A helper which belongs to the type rather than to one of its values is a static member of the block and is reached through the type: `RID.Current`, `FileExportFormat.TryFromCodeFenceLanguage`. Never name one `Parse` or `TryParse`: C# finds those of `Enum` first. - **Message Bus** - Singleton event bus for cross-component communication inside the .NET app - **Prompt injection reports** - The user hears once per action about what the filter removed, as soon as that action ends. Content which belongs to an action carries its scope from `PromptInjectionGuardService.BeginAction` down to where it is read or filtered; whatever is filtered without a scope is reported right away. Pass the scope as a parameter, never through a field or an `AsyncLocal`: the service serves the whole app, and the message bus delivers to other receivers in the execution context of whoever sends. - **Paths in stored data** - A stored path to a file which AI Studio keeps below the data directory, such as a transcript or a tokenizer copy, is relative to that directory, so that a backup or a copy of the data directory works on another computer, under another user name, or on another OS. Mark such a property with `[JsonConverter(typeof(DataDirectoryRelativePathConverter))]`, for a positional record parameter with `[property: ...]`; in memory, the path stays absolute. Better still, derive the path from IDs and store none, as `VisualBriefingStore` does. Paths to files of the user stay absolute. Chats stored before v26.10.1 are migrated by a compatibility shim, see `documentation/compatibility-shims/2026-10-relative-data-paths.md`. diff --git a/app/Build/Commands/Pdfium.cs b/app/Build/Commands/Pdfium.cs index 6593ec284..2409be994 100644 --- a/app/Build/Commands/Pdfium.cs +++ b/app/Build/Commands/Pdfium.cs @@ -14,7 +14,7 @@ public static class Pdfium public static async Task InstallAsync(RID rid, string version, bool offline) { - Console.Write($"- Installing Pdfium {version} for {rid.ToUserFriendlyName()} ..."); + Console.Write($"- Installing Pdfium {version} for {rid.UserFriendlyName} ..."); var cwd = Environment.GetRustRuntimeDirectory(); var pdfiumUrl = GetPdfiumDownloadUrl(rid, version); @@ -35,7 +35,7 @@ public static class Pdfium if (string.IsNullOrWhiteSpace(library.Path)) { - Console.WriteLine($" failed to find the library path for {rid.ToUserFriendlyName()}"); + Console.WriteLine($" failed to find the library path for {rid.UserFriendlyName}"); return; } @@ -50,7 +50,7 @@ public static class Pdfium using var response = await CLIENT.GetAsync(pdfiumUrl, HttpCompletionOption.ResponseHeadersRead); if (!response.IsSuccessStatusCode) { - Console.WriteLine($" failed to download Pdfium {version} for {rid.ToUserFriendlyName()} from {pdfiumUrl}"); + Console.WriteLine($" failed to download Pdfium {version} for {rid.UserFriendlyName} from {pdfiumUrl}"); return; } diff --git a/app/Build/Commands/UpdateMetadataCommands.cs b/app/Build/Commands/UpdateMetadataCommands.cs index ec0d4a3ea..10ecf325b 100644 --- a/app/Build/Commands/UpdateMetadataCommands.cs +++ b/app/Build/Commands/UpdateMetadataCommands.cs @@ -266,9 +266,9 @@ public sealed partial class UpdateMetadataCommands var pdfiumVersion = await this.ReadPdfiumVersion(); await Pdfium.InstallAsync(rid, pdfiumVersion, Environment.IsOfflineBuildRequested(offline)); - Console.Write($"- Start .NET build for {rid.ToUserFriendlyName()} ..."); - await this.ReadCommandOutput(pathApp, "dotnet", $"clean --configuration release --runtime {rid.AsMicrosoftRid()}"); - var dotnetBuildOutput = await this.ReadCommandOutput(pathApp, "dotnet", $"publish --configuration release --runtime {rid.AsMicrosoftRid()} --disable-build-servers --force"); + Console.Write($"- Start .NET build for {rid.UserFriendlyName} ..."); + await this.ReadCommandOutput(pathApp, "dotnet", $"clean --configuration release --runtime {rid.MicrosoftRid}"); + var dotnetBuildOutput = await this.ReadCommandOutput(pathApp, "dotnet", $"publish --configuration release --runtime {rid.MicrosoftRid} --disable-build-servers --force"); var dotnetBuildOutputLines = dotnetBuildOutput.Text.Split([global::System.Environment.NewLine], StringSplitOptions.RemoveEmptyEntries); var foundIssue = false; foreach (var buildOutputLine in dotnetBuildOutputLines) @@ -327,7 +327,7 @@ public sealed partial class UpdateMetadataCommands if (string.IsNullOrWhiteSpace(tauriSidecarArtifactName)) { - Console.WriteLine($"- Error: Unsupported rid '{rid.AsMicrosoftRid()}'."); + Console.WriteLine($"- Error: Unsupported rid '{rid.MicrosoftRid}'."); throw new CommandExitedException(1); } @@ -341,7 +341,7 @@ public sealed partial class UpdateMetadataCommands _ => "mindworkAIStudio", }; - var dotnetPublishedPath = Path.Combine(pathApp, "bin", "release", Environment.DOTNET_VERSION, rid.AsMicrosoftRid(), "publish", dotnetArtifactFilename); + var dotnetPublishedPath = Path.Combine(pathApp, "bin", "release", Environment.DOTNET_VERSION, rid.MicrosoftRid, "publish", dotnetArtifactFilename); var finalDestination = Path.Combine(dotnetArtifactPath, tauriSidecarArtifactName); if(File.Exists(dotnetPublishedPath)) diff --git a/app/Build/Commands/UpdateWebAssetsCommand.cs b/app/Build/Commands/UpdateWebAssetsCommand.cs index dfc2573a0..1d5bedf96 100644 --- a/app/Build/Commands/UpdateWebAssetsCommand.cs +++ b/app/Build/Commands/UpdateWebAssetsCommand.cs @@ -25,7 +25,7 @@ public sealed class UpdateWebAssetsCommand var rid = Environment.GetCurrentRid(); var cwd = Environment.GetAIStudioDirectory(); - var contentPath = Path.Join(cwd, "bin", "release", Environment.DOTNET_VERSION, rid.AsMicrosoftRid(), "publish", "wwwroot", "_content"); + var contentPath = Path.Join(cwd, "bin", "release", Environment.DOTNET_VERSION, rid.MicrosoftRid, "publish", "wwwroot", "_content"); var isMudBlazorDirectoryPresent = Directory.Exists(Path.Join(contentPath, "MudBlazor")); if (!isMudBlazorDirectoryPresent) diff --git a/app/Build/Commands/VerifyCommand.cs b/app/Build/Commands/VerifyCommand.cs index 05007f172..ac0f0c025 100644 --- a/app/Build/Commands/VerifyCommand.cs +++ b/app/Build/Commands/VerifyCommand.cs @@ -103,7 +103,7 @@ public sealed class VerifyCommand if (Directory.Exists(publishDirectory)) Directory.Delete(publishDirectory, recursive: true); - var publishExitCode = await CommandRunner.RunAsync(directory, "dotnet", $"publish --configuration release --runtime {rid.AsMicrosoftRid()} --output \"{publishDirectory}\" --nologo"); + var publishExitCode = await CommandRunner.RunAsync(directory, "dotnet", $"publish --configuration release --runtime {rid.MicrosoftRid} --output \"{publishDirectory}\" --nologo"); if (publishExitCode is not 0) return publishExitCode; diff --git a/app/Build/Tools/Environment.cs b/app/Build/Tools/Environment.cs index 99ce41316..1a961b59d 100644 --- a/app/Build/Tools/Environment.cs +++ b/app/Build/Tools/Environment.cs @@ -10,7 +10,7 @@ public static class Environment public const string BUILD_OFFLINE_ENVIRONMENT_VARIABLE = "AI_STUDIO_BUILD_OFFLINE"; public static readonly Encoding UTF8_NO_BOM = new UTF8Encoding(false); - private static readonly Dictionary ALL_RIDS = Enum.GetValues().Select(rid => new KeyValuePair(rid, rid.AsMicrosoftRid())).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + private static readonly Dictionary ALL_RIDS = Enum.GetValues().Select(rid => new KeyValuePair(rid, rid.MicrosoftRid)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); public static bool IsWorkingDirectoryValid() { diff --git a/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs b/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs index 1285c2a18..0c5a6b236 100644 --- a/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs +++ b/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs @@ -153,12 +153,12 @@ public sealed class AgentDataSourceSelection (ILogger if (!agentProvider.AllowsDataSourceAccess(this.SettingsManager, requiredDataSecurity, requiredConfidenceLevel)) { - logger.LogWarning($"The agent for data source selection uses provider '{agentProvider.InstanceName}' with confidence '{agentProvider.GetConfidenceLevel(this.SettingsManager).GetName()}', but the available data sources require data security '{requiredDataSecurity}' and provider confidence '{requiredConfidenceLevel.GetName()}'. The agent cannot select data sources."); + logger.LogWarning($"The agent for data source selection uses provider '{agentProvider.InstanceName}' with confidence '{agentProvider.GetConfidenceLevel(this.SettingsManager).Name}', but the available data sources require data security '{requiredDataSecurity}' and provider confidence '{requiredConfidenceLevel.Name}'. The agent cannot select data sources."); return []; } // 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()})."); + logger.LogInformation($"The agent for the data source selection uses the provider '{agentProvider.InstanceName}' ({agentProvider.UsedLLMProvider.Name}, confidence={agentProvider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level.Name})."); this.ProviderSettings = agentProvider; // diff --git a/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs b/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs index 9f38ba525..6de4a1d45 100644 --- a/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs +++ b/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs @@ -148,13 +148,13 @@ public sealed class AgentRetrievalContextValidation (ILogger logger, ILo }; } - logger.LogInformation($"The assistant plugin audit agent uses the provider '{provider.InstanceName}' ({provider.UsedLLMProvider.ToName()}, confidence={provider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level.GetName()})."); + logger.LogInformation($"The assistant plugin audit agent uses the provider '{provider.InstanceName}' ({provider.UsedLLMProvider.Name}, confidence={provider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level.Name})."); var promptPreview = await plugin.BuildAuditPromptPreviewAsync(token); var promptFallbackPreview = plugin.BuildAuditPromptFallbackPreview(); @@ -288,7 +288,7 @@ public sealed class AssistantAuditAgent(ILogger logger, ILo private static AssistantAuditResult NormalizeResult(AssistantAuditResult result) { var normalizedFindings = result.Findings; - var parsedLevel = AssistantAuditLevelExtensions.Parse(result.Level); + var parsedLevel = AssistantAuditLevel.ParseOrUnknown(result.Level); var lowestFindingLevel = GetMostSevereFindingLevel(normalizedFindings); if (lowestFindingLevel != AssistantAuditLevel.UNKNOWN && (parsedLevel == AssistantAuditLevel.UNKNOWN || lowestFindingLevel < parsedLevel)) parsedLevel = lowestFindingLevel; diff --git a/app/MindWork AI Studio/Agents/AssistantAudit/AssistantAuditLevelExtensions.cs b/app/MindWork AI Studio/Agents/AssistantAudit/AssistantAuditLevelExtensions.cs index b0d4fb25d..ddcb3185c 100644 --- a/app/MindWork AI Studio/Agents/AssistantAudit/AssistantAuditLevelExtensions.cs +++ b/app/MindWork AI Studio/Agents/AssistantAudit/AssistantAuditLevelExtensions.cs @@ -8,7 +8,7 @@ public static class AssistantAuditLevelExtensions extension(AssistantAuditLevel level) { - public string GetName() => level switch + public string Name => level switch { AssistantAuditLevel.DANGEROUS => TB("Dangerous"), AssistantAuditLevel.CAUTION => TB("Concerning"), @@ -16,7 +16,7 @@ public static class AssistantAuditLevelExtensions _ => TB("Unknown"), }; - public Severity GetSeverity() => level switch + public Severity Severity => level switch { AssistantAuditLevel.DANGEROUS => Severity.Error, AssistantAuditLevel.CAUTION => Severity.Warning, @@ -24,7 +24,7 @@ public static class AssistantAuditLevelExtensions _ => Severity.Info, }; - public Color GetColor() => level switch + public Color Color => level switch { AssistantAuditLevel.DANGEROUS => Color.Error, AssistantAuditLevel.CAUTION => Color.Warning, @@ -32,19 +32,19 @@ public static class AssistantAuditLevelExtensions _ => Color.Default, }; - public string GetIcon() => level switch + public string Icon => level switch { AssistantAuditLevel.DANGEROUS => Icons.Material.Filled.Dangerous, AssistantAuditLevel.CAUTION => Icons.Material.Filled.Warning, AssistantAuditLevel.SAFE => Icons.Material.Filled.Verified, _ => Icons.Material.Filled.HelpOutline, }; - } - /// - /// Parses an audit level string and falls back to when parsing fails. - /// - /// The audit level text to parse. - /// The parsed audit level, or for null, empty, or invalid values. - public static AssistantAuditLevel Parse(string? value) => Enum.TryParse(value, true, out var level) ? level : AssistantAuditLevel.UNKNOWN; + /// + /// Parses an audit level string and falls back to when parsing fails. + /// + /// The audit level text to parse. + /// The parsed audit level, or for null, empty, or invalid values. + public static AssistantAuditLevel ParseOrUnknown(string? value) => Enum.TryParse(value, true, out var parsedLevel) ? parsedLevel : AssistantAuditLevel.UNKNOWN; + } } diff --git a/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor b/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor index d653cb118..d5bc2393c 100644 --- a/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor +++ b/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor @@ -35,7 +35,7 @@ - + @if (!this.isMeetingVirtual) @@ -52,5 +52,5 @@ } - + \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor.cs b/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor.cs index a27a80a6f..b39c3e51a 100644 --- a/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor.cs +++ b/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor.cs @@ -426,7 +426,7 @@ public partial class AssistantAgenda : AssistantBaseCore - The planned duration is '{this.inputDuration}'. - The planned start time is '{this.inputStartTime}'. {this.PromptGettingToKnowEachOther()} - - The number of participants is '{this.numberParticipants.Name()}'. + - The number of participants is '{this.numberParticipants.Name}'. {this.PromptActiveParticipation()} {this.PromptVirtualMeeting()} {this.PromptPhysicalMeeting()} @@ -451,7 +451,7 @@ public partial class AssistantAgenda : AssistantBaseCore if(this.selectedTargetLanguage is CommonLanguages.OTHER) return this.customTargetLanguage; - return this.selectedTargetLanguage.Name(); + return this.selectedTargetLanguage.Name; } private string PromptPhysicalMeeting() diff --git a/app/MindWork AI Studio/Assistants/Agenda/NumberParticipantsExtensions.cs b/app/MindWork AI Studio/Assistants/Agenda/NumberParticipantsExtensions.cs index e582ec8fe..6ea596eb4 100644 --- a/app/MindWork AI Studio/Assistants/Agenda/NumberParticipantsExtensions.cs +++ b/app/MindWork AI Studio/Assistants/Agenda/NumberParticipantsExtensions.cs @@ -6,7 +6,7 @@ public static class NumberParticipantsExtensions extension(NumberParticipants numberParticipants) { - public string Name() => numberParticipants switch + public string Name => numberParticipants switch { NumberParticipants.NOT_SPECIFIED => TB("Please select how many participants are expected"), diff --git a/app/MindWork AI Studio/Assistants/AssistantBase.razor b/app/MindWork AI Studio/Assistants/AssistantBase.razor index 6a8a70cf4..dfae2592d 100644 --- a/app/MindWork AI Studio/Assistants/AssistantBase.razor +++ b/app/MindWork AI Studio/Assistants/AssistantBase.razor @@ -131,7 +131,7 @@ @foreach (var assistant in this.VisibleSendToAssistants) { - @assistant.Name() + @assistant.Name } @@ -163,7 +163,7 @@ @foreach (var assistant in this.VisibleSendToAssistants) { - @assistant.Name() + @assistant.Name } diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor index e07800651..d97e7ef3e 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor @@ -63,7 +63,7 @@ @foreach (var source in Enum.GetValues()) { - @source.Name() + @source.Name } @@ -149,7 +149,7 @@ else @foreach (var mode in Enum.GetValues()) { - @mode.Name() + @mode.Name } @@ -157,16 +157,16 @@ else @if (this.outputMode is BatchProcessingOutputMode.INDIVIDUAL_FILES) { - @foreach (var format in FileExportFormatExtensions.ANSWER_FORMATS) + @foreach (var format in FileExportFormat.AnswerFormats) { - @format.ToName() + @format.Name } - @(string.Format(T("Each answer is stored as its own file. Those files are named after the document, e.g., the answer for report.pdf is stored as report_result{0}."), this.resultFileFormat.ToFileExtension())) + @(string.Format(T("Each answer is stored as its own file. Those files are named after the document, e.g., the answer for report.pdf is stored as report_result{0}."), this.resultFileFormat.FileExtension)) } else @@ -179,7 +179,7 @@ else @foreach (var separator in Enum.GetValues()) { - @separator.Name() + @separator.Name } diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Persistence.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Persistence.cs index 9c07c67f7..df39ca27d 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Persistence.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Persistence.cs @@ -244,7 +244,7 @@ public partial class AssistantBatchProcessing /// private string CreateResultFileName(string sourceFileName) { - var extension = this.resultFileFormat.ToFileExtension(); + var extension = this.resultFileFormat.FileExtension; var stem = Path.GetFileNameWithoutExtension(sourceFileName); var candidate = $"{stem}{RESULT_FILE_SUFFIX}{extension}"; diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Run.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Run.cs index cfcdbebe6..57b5032d5 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Run.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Run.cs @@ -21,7 +21,7 @@ public partial class AssistantBatchProcessing // hundreds of times, and starting without it would spend time and tokens on answers we // cannot write anywhere: // - if (this.outputMode is BatchProcessingOutputMode.INDIVIDUAL_FILES && this.resultFileFormat.UsesPandoc()) + if (this.outputMode is BatchProcessingOutputMode.INDIVIDUAL_FILES && this.resultFileFormat.UsesPandoc) { var pandocState = await this.PandocAvailability.EnsureAvailabilityAsync(showSuccessMessage: false, showDialog: true); if (!pandocState.IsAvailable) @@ -270,7 +270,7 @@ public partial class AssistantBatchProcessing // var resultText = this.DisclosureService.AddDisclosureToMarkdown(aiAnswer); var resultFilePath = Path.Join(resolvedOutputDirectory, this.CreateResultFileName(fileResult.FileName)); - if (this.resultFileFormat.UsesPandoc()) + if (this.resultFileFormat.UsesPandoc) { // // Pandoc reports a failure instead of throwing, because one document which @@ -283,7 +283,7 @@ public partial class AssistantBatchProcessing } } else - await File.WriteAllTextAsync(resultFilePath, resultText, this.resultFileFormat.ToFileEncoding(), CancellationToken.None); + await File.WriteAllTextAsync(resultFilePath, resultText, this.resultFileFormat.FileEncoding, CancellationToken.None); this.FinishFileResult(fileResult, BatchProcessingFileStatus.DONE, Path.GetFileName(resultFilePath)); } diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs index f7cabfa87..03726a3fd 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs @@ -35,7 +35,7 @@ public partial class AssistantBatchProcessing || this.csvSeparator is not BatchProcessingCsvSeparator.CUSTOM) return null; - if (!BatchProcessingCsvSeparatorExtensions.IsValidCustomSeparator(separator)) + if (!BatchProcessingCsvSeparator.IsValidCustomSeparator(separator)) return T("Please enter exactly one punctuation or symbol character. Letters, numbers, spaces, quotation marks, and line breaks cannot be used as CSV separators."); return null; diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingCsvSeparatorExtensions.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingCsvSeparatorExtensions.cs index 2d3225dbc..6f7b8e7aa 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingCsvSeparatorExtensions.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingCsvSeparatorExtensions.cs @@ -8,7 +8,7 @@ public static class BatchProcessingCsvSeparatorExtensions extension(BatchProcessingCsvSeparator separator) { - public string Name() => separator switch + public string Name => separator switch { BatchProcessingCsvSeparator.COMMA => TB("Comma (,)"), BatchProcessingCsvSeparator.SEMICOLON => TB("Semicolon (;)"), @@ -25,20 +25,20 @@ public static class BatchProcessingCsvSeparatorExtensions BatchProcessingCsvSeparator.SEMICOLON => ';', BatchProcessingCsvSeparator.PIPE => '|', BatchProcessingCsvSeparator.TAB => '\t', - BatchProcessingCsvSeparator.CUSTOM when IsValidCustomSeparator(customSeparator) => customSeparator[0], + BatchProcessingCsvSeparator.CUSTOM when BatchProcessingCsvSeparator.IsValidCustomSeparator(customSeparator) => customSeparator[0], _ => DEFAULT_SEPARATOR, }; - } - internal static bool IsValidCustomSeparator(string separator) - { - if (string.IsNullOrEmpty(separator) || separator.Length is not 1) - return false; + internal static bool IsValidCustomSeparator(string customSeparator) + { + if (string.IsNullOrEmpty(customSeparator) || customSeparator.Length is not 1) + return false; - var character = separator[0]; - return !char.IsLetterOrDigit(character) - && !char.IsWhiteSpace(character) - && character is not '"' and not '\r' and not '\n'; + var character = customSeparator[0]; + return !char.IsLetterOrDigit(character) + && !char.IsWhiteSpace(character) + && character is not '"' and not '\r' and not '\n'; + } } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingOutputModeExtensions.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingOutputModeExtensions.cs index 0bf81ea2d..ce96fb710 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingOutputModeExtensions.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingOutputModeExtensions.cs @@ -6,7 +6,7 @@ public static class BatchProcessingOutputModeExtensions extension(BatchProcessingOutputMode outputMode) { - public string Name() => outputMode switch + public string Name => outputMode switch { BatchProcessingOutputMode.INDIVIDUAL_FILES => TB("One file per document"), BatchProcessingOutputMode.TABLE_ONLY => TB("One CSV results table, where each answer becomes one row"), diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingPromptSourceExtensions.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingPromptSourceExtensions.cs index e8c11cc99..3fde0d9a7 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingPromptSourceExtensions.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/BatchProcessingPromptSourceExtensions.cs @@ -6,7 +6,7 @@ public static class BatchProcessingPromptSourceExtensions extension(BatchProcessingPromptSource promptSource) { - public string Name() => promptSource switch + public string Name => promptSource switch { BatchProcessingPromptSource.FREE_PROMPT => TB("Use a free prompt"), BatchProcessingPromptSource.POLICY => TB("Use a document analysis policy"), diff --git a/app/MindWork AI Studio/Assistants/BiasDay/BiasOfTheDayAssistant.razor b/app/MindWork AI Studio/Assistants/BiasDay/BiasOfTheDayAssistant.razor index 8f582ebe3..810f654e7 100644 --- a/app/MindWork AI Studio/Assistants/BiasDay/BiasOfTheDayAssistant.razor +++ b/app/MindWork AI Studio/Assistants/BiasDay/BiasOfTheDayAssistant.razor @@ -10,5 +10,5 @@ @T("Blog post of Buster Benson:") "Cognitive bias cheat sheet" - + \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/BiasDay/BiasOfTheDayAssistant.razor.cs b/app/MindWork AI Studio/Assistants/BiasDay/BiasOfTheDayAssistant.razor.cs index d6a524238..b4fcb9078 100644 --- a/app/MindWork AI Studio/Assistants/BiasDay/BiasOfTheDayAssistant.razor.cs +++ b/app/MindWork AI Studio/Assistants/BiasDay/BiasOfTheDayAssistant.razor.cs @@ -18,10 +18,10 @@ public partial class BiasOfTheDayAssistant : AssistantBaseCore $""" You are a friendly, helpful expert on cognitive bias. You studied psychology and have a lot of experience. You explain a bias every day. Today's bias belongs to - the category: "{this.biasOfTheDay.Category.ToName()}". We have the following + the category: "{this.biasOfTheDay.Category.Name}". We have the following thoughts on this category: - {this.biasOfTheDay.Category.GetThoughts()} + {this.biasOfTheDay.Category.Thoughts} Today's bias is: {this.biasOfTheDay.Description} @@ -124,7 +124,7 @@ public partial class BiasOfTheDayAssistant : AssistantBaseCore } - + @if (!this.createChatLauncher) { @@ -59,11 +59,11 @@ @foreach (var component in ASSISTANT_COMPONENT_OPTIONS) { - @component.GetDisplayName() + @component.DisplayName } - + @@ -201,8 +201,8 @@ else } else if (this.AuditCompleted) { - - @this.pluginAudit.Level.GetName(): @this.pluginAudit.Summary + + @this.pluginAudit.Level.Name: @this.pluginAudit.Summary } else diff --git a/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor.cs b/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor.cs index fd4b38241..28feb46a3 100644 --- a/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor.cs +++ b/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor.cs @@ -520,14 +520,14 @@ public partial class AssistantBuilder : AssistantBaseCore string.Empty, AssistantCategory.OTHER => this.customCategory, - _ => this.selectedCategory.Name(), + _ => this.selectedCategory.Name, }; private string GetSelectedOutputLanguageName() => this.selectedOutputLanguage switch { CommonLanguages.AS_IS => string.Empty, CommonLanguages.OTHER => this.customOutputLanguage, - _ => this.selectedOutputLanguage.Name(), + _ => this.selectedOutputLanguage.Name, }; private string GetSelectedAssistantComponentText(IReadOnlyList? selectedValues) @@ -625,7 +625,7 @@ public partial class AssistantBuilder : AssistantBaseCore(typeName, out var type)) - return type.GetDisplayName(); + return type.DisplayName; return typeName ?? string.Empty; } @@ -726,7 +726,7 @@ public partial class AssistantBuilder : AssistantBaseCore language switch + public string Name => language switch { CommonCodingLanguages.NONE => TB("None"), diff --git a/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor b/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor index 6955c7f1d..2bcbe95c7 100644 --- a/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor +++ b/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor @@ -29,8 +29,8 @@ else @if (this.audit is not null && this.audit.Level is not AssistantAuditLevel.SAFE) { - - @this.audit.Level.GetName().ToUpperInvariant(): @this.audit.Summary + + @this.audit.Level.Name.ToUpperInvariant(): @this.audit.Summary } diff --git a/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor b/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor index f620905b7..6ea4d7c2a 100644 --- a/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor +++ b/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor @@ -20,6 +20,6 @@ } - - + + \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor.cs b/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor.cs index 34388096c..469aba1bb 100644 --- a/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor.cs +++ b/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor.cs @@ -17,7 +17,7 @@ public partial class AssistantEMail : AssistantBaseCore $""" You are an automated system that writes emails. {this.SystemPromptHistory()} The user provides you with bullet points on what - he want to address in the response. Regarding the writing style of the email: {this.selectedWritingStyle.Prompt()} + he want to address in the response. Regarding the writing style of the email: {this.selectedWritingStyle.Prompt} {this.SystemPromptGreeting()} {this.SystemPromptName()} You write the email in the following language: {this.SystemPromptLanguage()}. """; @@ -227,7 +227,7 @@ public partial class AssistantEMail : AssistantBaseCore style switch + public string Name => style switch { WritingStyles.ACADEMIC => TB("Academic"), WritingStyles.PERSONAL => TB("Personal"), @@ -16,7 +16,7 @@ public static class WritingStylesExtensions _ => TB("Not specified"), }; - public string Prompt() => style switch + public string Prompt => style switch { WritingStyles.ACADEMIC => "Use an academic style for communication in an academic context like between students and professors.", WritingStyles.PERSONAL => "Use a personal style for communication between friends and family.", diff --git a/app/MindWork AI Studio/Assistants/ERI/AllowedLLMProvidersExtensions.cs b/app/MindWork AI Studio/Assistants/ERI/AllowedLLMProvidersExtensions.cs index 0156c7b64..6c35ab001 100644 --- a/app/MindWork AI Studio/Assistants/ERI/AllowedLLMProvidersExtensions.cs +++ b/app/MindWork AI Studio/Assistants/ERI/AllowedLLMProvidersExtensions.cs @@ -6,7 +6,7 @@ public static class AllowedLLMProvidersExtensions extension(AllowedLLMProviders provider) { - public string Description() => provider switch + public string Description => provider switch { AllowedLLMProviders.NONE => TB("Please select what kind of LLM provider are allowed for this data source"), AllowedLLMProviders.ANY => TB("Any LLM provider is allowed: users might choose a cloud-based or a self-hosted provider"), diff --git a/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor b/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor index 8c330cd7a..91062fa99 100644 --- a/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor +++ b/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor @@ -97,7 +97,7 @@ else @foreach (var language in Enum.GetValues()) { - @language.Name() + @language.Name } @@ -130,7 +130,7 @@ else @foreach (var dataSource in Enum.GetValues()) { - @dataSource.Name() + @dataSource.Name } @@ -181,7 +181,7 @@ else @foreach (var authMethod in Enum.GetValues()) { - @authMethod.Name() + @authMethod.Name } @@ -194,7 +194,7 @@ else @foreach (var os in Enum.GetValues()) { - @os.Name() + @os.Name } @@ -208,7 +208,7 @@ else @foreach (var option in Enum.GetValues()) { - @option.Description() + @option.Description } diff --git a/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor.cs b/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor.cs index 0d1d4902a..d41d61d37 100644 --- a/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor.cs +++ b/app/MindWork AI Studio/Assistants/ERI/AssistantERI.razor.cs @@ -378,7 +378,7 @@ public partial class AssistantERI : AssistantBaseCore /// /// Gets whether the selected ERI specification cannot be saved. /// - private bool IsSpecificationSavingDisabled => !this.selectedERIVersion.WasSpecificationSelected() || this.IsERIInputDisabled; + private bool IsSpecificationSavingDisabled => !this.selectedERIVersion.WasSpecificationSelected || this.IsERIInputDisabled; /// /// Lets the user save the selected ERI specification, a copy of the one the app carries. @@ -389,7 +389,7 @@ public partial class AssistantERI : AssistantBaseCore /// private async Task SaveSpecificationAsync() { - var specificationPath = this.selectedERIVersion.SpecificationURL(); + var specificationPath = this.selectedERIVersion.SpecificationURL; var response = await this.RustService.SaveFile(T("Save the ERI specification"), [FileTypes.JSON], Path.GetFileName(specificationPath)); if (response.UserCancelled) return; diff --git a/app/MindWork AI Studio/Assistants/ERI/AuthExtensions.cs b/app/MindWork AI Studio/Assistants/ERI/AuthExtensions.cs index 789132bf2..973cfec48 100644 --- a/app/MindWork AI Studio/Assistants/ERI/AuthExtensions.cs +++ b/app/MindWork AI Studio/Assistants/ERI/AuthExtensions.cs @@ -6,7 +6,7 @@ public static class AuthExtensions extension(Auth auth) { - public string Name() => auth switch + public string Name => auth switch { Auth.NONE => TB("No login necessary: useful for public data sources"), @@ -17,7 +17,7 @@ public static class AuthExtensions _ => TB("Unknown login method") }; - public string ToPrompt() => auth switch + public string Prompt => auth switch { Auth.NONE => "No login is necessary, the data source is public.", diff --git a/app/MindWork AI Studio/Assistants/ERI/DataSourcesExtensions.cs b/app/MindWork AI Studio/Assistants/ERI/DataSourcesExtensions.cs index 133033dce..cad97819d 100644 --- a/app/MindWork AI Studio/Assistants/ERI/DataSourcesExtensions.cs +++ b/app/MindWork AI Studio/Assistants/ERI/DataSourcesExtensions.cs @@ -6,7 +6,7 @@ public static class DataSourcesExtensions extension(DataSources dataSource) { - public string Name() => dataSource switch + public string Name => dataSource switch { DataSources.NONE => TB("No data source selected"), DataSources.CUSTOM => TB("Custom description"), diff --git a/app/MindWork AI Studio/Assistants/ERI/ERIServerPrompt.cs b/app/MindWork AI Studio/Assistants/ERI/ERIServerPrompt.cs index 8e38e5522..cb32dfd4f 100644 --- a/app/MindWork AI Studio/Assistants/ERI/ERIServerPrompt.cs +++ b/app/MindWork AI Studio/Assistants/ERI/ERIServerPrompt.cs @@ -58,7 +58,7 @@ internal sealed class ERIServerPrompt // Introduction // --------------------------------- // - var programmingLanguage = this.ProgrammingLanguage is ProgrammingLanguages.OTHER ? this.OtherProgrammingLanguage : this.ProgrammingLanguage.ToPrompt(); + var programmingLanguage = this.ProgrammingLanguage is ProgrammingLanguages.OTHER ? this.OtherProgrammingLanguage : this.ProgrammingLanguage.Prompt; sb.Append($""" # Introduction You are an experienced {programmingLanguage} developer. Your task is to implement an API server in @@ -172,7 +172,7 @@ internal sealed class ERIServerPrompt { sb.Append($""" - - {auth.ToPrompt()} + - {auth.Prompt} """); } @@ -192,7 +192,7 @@ internal sealed class ERIServerPrompt { sb.Append($""" - The server will run on {this.OperatingSystem.ToPrompt()} operating systems. Keep + The server will run on {this.OperatingSystem.Prompt} operating systems. Keep this in mind when implementing the SSO with Kerberos. """); } diff --git a/app/MindWork AI Studio/Assistants/ERI/ERIVersionExtensions.cs b/app/MindWork AI Studio/Assistants/ERI/ERIVersionExtensions.cs index 2cb7578da..d6a34ca42 100644 --- a/app/MindWork AI Studio/Assistants/ERI/ERIVersionExtensions.cs +++ b/app/MindWork AI Studio/Assistants/ERI/ERIVersionExtensions.cs @@ -4,15 +4,18 @@ public static class ERIVersionExtensions { extension(ERIVersion version) { - public Task ReadSpecification(WebRootFiles webRootFiles) => webRootFiles.ReadTextAsync(version.SpecificationURL()); + public Task ReadSpecification(WebRootFiles webRootFiles) => webRootFiles.ReadTextAsync(version.SpecificationURL); - public string SpecificationURL() + public string SpecificationURL { - var nameLower = version.ToString().ToLowerInvariant(); - var filename = $"{nameLower}.json"; - return $"specs/eri/{filename}"; + get + { + var nameLower = version.ToString().ToLowerInvariant(); + var filename = $"{nameLower}.json"; + return $"specs/eri/{filename}"; + } } - public bool WasSpecificationSelected() => version != ERIVersion.NONE; + public bool WasSpecificationSelected => version != ERIVersion.NONE; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/ERI/OperatingSystemExtensions.cs b/app/MindWork AI Studio/Assistants/ERI/OperatingSystemExtensions.cs index 6259d7559..e7aeb6b91 100644 --- a/app/MindWork AI Studio/Assistants/ERI/OperatingSystemExtensions.cs +++ b/app/MindWork AI Studio/Assistants/ERI/OperatingSystemExtensions.cs @@ -6,7 +6,7 @@ public static class OperatingSystemExtensions extension(OperatingSystem os) { - public string Name() => os switch + public string Name => os switch { OperatingSystem.NONE => TB("No operating system specified"), @@ -16,7 +16,7 @@ public static class OperatingSystemExtensions _ => TB("Unknown operating system") }; - public string ToPrompt() => os switch + public string Prompt => os switch { OperatingSystem.NONE => "No operating system specified", diff --git a/app/MindWork AI Studio/Assistants/ERI/ProgrammingLanguagesExtensions.cs b/app/MindWork AI Studio/Assistants/ERI/ProgrammingLanguagesExtensions.cs index ffd1626de..6128732e9 100644 --- a/app/MindWork AI Studio/Assistants/ERI/ProgrammingLanguagesExtensions.cs +++ b/app/MindWork AI Studio/Assistants/ERI/ProgrammingLanguagesExtensions.cs @@ -6,7 +6,7 @@ public static class ProgrammingLanguagesExtensions extension(ProgrammingLanguages language) { - public string Name() => language switch + public string Name => language switch { ProgrammingLanguages.NONE => TB("No programming language selected"), @@ -26,7 +26,7 @@ public static class ProgrammingLanguagesExtensions _ => TB("Unknown") }; - public string ToPrompt() => language switch + public string Prompt => language switch { ProgrammingLanguages.NONE => "No programming language selected", diff --git a/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor b/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor index a6a093670..ac3c25516 100644 --- a/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor +++ b/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor.cs b/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor.cs index c0c427395..cec8522d3 100644 --- a/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor.cs +++ b/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor.cs @@ -124,7 +124,7 @@ public partial class AssistantGrammarSpelling : AssistantBaseCore "the source language", CommonLanguages.OTHER => this.customTargetLanguage, - _ => $"{this.selectedTargetLanguage.Name()}", + _ => $"{this.selectedTargetLanguage.Name}", }; if (string.IsNullOrWhiteSpace(lang)) diff --git a/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor b/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor index 0655db52f..e94184b3b 100644 --- a/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor +++ b/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor @@ -2,7 +2,7 @@ @using AIStudio.Settings @inherits AssistantBaseCore - + @if (this.isLoading) { diff --git a/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor.cs b/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor.cs index 3731d00de..6a9142a22 100644 --- a/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor.cs +++ b/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor.cs @@ -190,7 +190,7 @@ public partial class AssistantI18N : AssistantBaseCore private string SystemPromptLanguage() => this.activeSystemPromptLanguage ?? (this.selectedTargetLanguage switch { CommonLanguages.OTHER => this.customTargetLanguage, - _ => $"{this.selectedTargetLanguage.Name()}", + _ => $"{this.selectedTargetLanguage.Name}", }); private async Task OnLanguagePluginChanged(Guid pluginId) @@ -215,9 +215,9 @@ public partial class AssistantI18N : AssistantBaseCore this.loadingIssue = string.Format(T("Was not able to load the language plugin for comparison ({0}). Please select a valid, loaded & running language plugin."), this.selectedLanguagePluginId); this.selectedLanguagePlugin = null; } - else if (comparisonPlugin.IETFTag != this.selectedTargetLanguage.ToIETFTag()) + else if (comparisonPlugin.IETFTag != this.selectedTargetLanguage.IETFTag) { - this.loadingIssue = string.Format(T("The selected language plugin for comparison uses the IETF tag '{0}' which does not match the selected target language '{1}'. Please select a valid, loaded & running language plugin which matches the target language."), comparisonPlugin.IETFTag, this.selectedTargetLanguage.ToIETFTag()); + this.loadingIssue = string.Format(T("The selected language plugin for comparison uses the IETF tag '{0}' which does not match the selected target language '{1}'. Please select a valid, loaded & running language plugin which matches the target language."), comparisonPlugin.IETFTag, this.selectedTargetLanguage.IETFTag); this.selectedLanguagePlugin = null; } else @@ -356,7 +356,7 @@ public partial class AssistantI18N : AssistantBaseCore if(this.selectedLanguagePlugin is null) return; - if (this.selectedLanguagePlugin.IETFTag != this.selectedTargetLanguage.ToIETFTag()) + if (this.selectedLanguagePlugin.IETFTag != this.selectedTargetLanguage.IETFTag) return; var addedContentSnapshot = this.addedContent.ToArray(); diff --git a/app/MindWork AI Studio/Assistants/IconFinder/AssistantIconFinder.razor b/app/MindWork AI Studio/Assistants/IconFinder/AssistantIconFinder.razor index 36466a563..9cc3680bd 100644 --- a/app/MindWork AI Studio/Assistants/IconFinder/AssistantIconFinder.razor +++ b/app/MindWork AI Studio/Assistants/IconFinder/AssistantIconFinder.razor @@ -8,13 +8,13 @@ @foreach (var source in Enum.GetValues()) { - @source.Name() + @source.Name } @if (this.selectedIconSource is not IconSources.GENERIC) { - + @T("Open website") } diff --git a/app/MindWork AI Studio/Assistants/IconFinder/AssistantIconFinder.razor.cs b/app/MindWork AI Studio/Assistants/IconFinder/AssistantIconFinder.razor.cs index bd0c34f09..85130d2bc 100644 --- a/app/MindWork AI Studio/Assistants/IconFinder/AssistantIconFinder.razor.cs +++ b/app/MindWork AI Studio/Assistants/IconFinder/AssistantIconFinder.razor.cs @@ -31,7 +31,7 @@ public partial class AssistantIconFinder : AssistantBaseCore $""" - {string.Format(T("Find icon suggestions on {0} for the following context:"), this.selectedIconSource.Name())} + {string.Format(T("Find icon suggestions on {0} for the following context:"), this.selectedIconSource.Name)} {this.inputContext} """; @@ -98,7 +98,7 @@ public partial class AssistantIconFinder : AssistantBaseCore iconSource switch + public string Name => iconSource switch { IconSources.FLAT_ICON => "Flaticon", IconSources.FONT_AWESOME => "Font Awesome", @@ -16,7 +16,7 @@ public static class IconSourceExtensions _ => "Generic", }; - public string Prompt() => iconSource switch + public string Prompt => iconSource switch { IconSources.FLAT_ICON => "My icon source is Flaticon.", IconSources.FONT_AWESOME => "I look for an icon on Font Awesome. Please provide just valid icon names. Valid icon names are using the format `fa-icon-name`.", @@ -28,7 +28,7 @@ public static class IconSourceExtensions _ => string.Empty, }; - public string URL() => iconSource switch + public string URL => iconSource switch { IconSources.FLAT_ICON => "https://www.flaticon.com/", IconSources.FONT_AWESOME => "https://fontawesome.com/", diff --git a/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor b/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor index 71b4b9d09..885368e52 100644 --- a/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor +++ b/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor @@ -16,5 +16,5 @@ - + \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor.cs b/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor.cs index b716ada7c..3c7114660 100644 --- a/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor.cs +++ b/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor.cs @@ -212,7 +212,7 @@ public partial class AssistantJobPostings : AssistantBaseCore - + \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor.cs b/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor.cs index 2bf37a24e..bcadcbca5 100644 --- a/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor.cs +++ b/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor.cs @@ -182,7 +182,7 @@ public partial class AssistantMyTasks : AssistantBaseCore if(this.selectedTargetLanguage is CommonLanguages.OTHER) return this.customTargetLanguage; - return this.selectedTargetLanguage.Name(); + return this.selectedTargetLanguage.Name; } private ContentBlock CloneHiddenUserBlockWithoutAttachments(ContentBlock block) diff --git a/app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor b/app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor index d6bb540b3..7bcbdd8ce 100644 --- a/app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor +++ b/app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor @@ -18,7 +18,7 @@ UserAttributes="@USER_INPUT_ATTRIBUTES"/> "the source language of the input prompt", CommonLanguages.OTHER => this.customTargetLanguage, - _ => this.selectedTargetLanguage.Name(), + _ => this.selectedTargetLanguage.Name, }; if (string.IsNullOrWhiteSpace(language)) diff --git a/app/MindWork AI Studio/Assistants/RewriteImprove/AssistantRewriteImprove.razor b/app/MindWork AI Studio/Assistants/RewriteImprove/AssistantRewriteImprove.razor index e302cdc24..e9f41f707 100644 --- a/app/MindWork AI Studio/Assistants/RewriteImprove/AssistantRewriteImprove.razor +++ b/app/MindWork AI Studio/Assistants/RewriteImprove/AssistantRewriteImprove.razor @@ -3,7 +3,7 @@ - - - + + + \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/RewriteImprove/AssistantRewriteImprove.razor.cs b/app/MindWork AI Studio/Assistants/RewriteImprove/AssistantRewriteImprove.razor.cs index 910dfa816..973eff564 100644 --- a/app/MindWork AI Studio/Assistants/RewriteImprove/AssistantRewriteImprove.razor.cs +++ b/app/MindWork AI Studio/Assistants/RewriteImprove/AssistantRewriteImprove.razor.cs @@ -19,7 +19,7 @@ public partial class AssistantRewriteImprove : AssistantBaseCore "the source language", CommonLanguages.OTHER => this.customTargetLanguage, - _ => $"{this.selectedTargetLanguage.Name()}", + _ => $"{this.selectedTargetLanguage.Name}", }; if (string.IsNullOrWhiteSpace(lang)) diff --git a/app/MindWork AI Studio/Assistants/RewriteImprove/SentenceStructureExtensions.cs b/app/MindWork AI Studio/Assistants/RewriteImprove/SentenceStructureExtensions.cs index 4f3019b41..12b5106e1 100644 --- a/app/MindWork AI Studio/Assistants/RewriteImprove/SentenceStructureExtensions.cs +++ b/app/MindWork AI Studio/Assistants/RewriteImprove/SentenceStructureExtensions.cs @@ -6,7 +6,7 @@ public static class SentenceStructureExtensions extension(SentenceStructure sentenceStructure) { - public string Name() => sentenceStructure switch + public string Name => sentenceStructure switch { SentenceStructure.ACTIVE => TB("Active voice"), SentenceStructure.PASSIVE => TB("Passive voice"), @@ -14,7 +14,7 @@ public static class SentenceStructureExtensions _ => TB("Not Specified"), }; - public string Prompt() => sentenceStructure switch + public string Prompt => sentenceStructure switch { SentenceStructure.ACTIVE => " Use an active voice for the sentence structure.", SentenceStructure.PASSIVE => " Use a passive voice for the sentence structure.", diff --git a/app/MindWork AI Studio/Assistants/RewriteImprove/WritingStylesExtensions.cs b/app/MindWork AI Studio/Assistants/RewriteImprove/WritingStylesExtensions.cs index 1bd047264..cbf33a384 100644 --- a/app/MindWork AI Studio/Assistants/RewriteImprove/WritingStylesExtensions.cs +++ b/app/MindWork AI Studio/Assistants/RewriteImprove/WritingStylesExtensions.cs @@ -6,7 +6,7 @@ public static class WritingStylesExtensions extension(WritingStyles style) { - public string Name() => style switch + public string Name => style switch { WritingStyles.EVERYDAY => TB("Everyday (personal texts, social media)"), WritingStyles.BUSINESS => TB("Business (business emails, reports, presentations)"), @@ -22,7 +22,7 @@ public static class WritingStylesExtensions _ => TB("Not specified"), }; - public string Prompt() => style switch + public string Prompt => style switch { WritingStyles.EVERYDAY => "Use a everyday style like for personal texts, social media, and informal communication.", WritingStyles.BUSINESS => "Use a business style like for business emails, reports, and presentations. Most important is clarity and professionalism.", diff --git a/app/MindWork AI Studio/Assistants/SWOTAnalysis/AssistantSWOTAnalysis.razor b/app/MindWork AI Studio/Assistants/SWOTAnalysis/AssistantSWOTAnalysis.razor index b2bc2accf..1091cbbb7 100644 --- a/app/MindWork AI Studio/Assistants/SWOTAnalysis/AssistantSWOTAnalysis.razor +++ b/app/MindWork AI Studio/Assistants/SWOTAnalysis/AssistantSWOTAnalysis.razor @@ -34,6 +34,6 @@
- +
\ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisCategoryExtensions.cs b/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisCategoryExtensions.cs index 47d10dd1c..34a1e6762 100644 --- a/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisCategoryExtensions.cs +++ b/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisCategoryExtensions.cs @@ -7,7 +7,7 @@ internal static class SwotAnalysisCategoryExtensions /// /// The name of the category in the JSON the models read and write, e.g., "strengths". /// - public string JsonName() => category switch + public string JsonName => category switch { SwotAnalysisCategory.STRENGTHS => "strengths", SwotAnalysisCategory.WEAKNESSES => "weaknesses", @@ -20,7 +20,7 @@ internal static class SwotAnalysisCategoryExtensions /// /// The letter the factor IDs of the category start with, e.g., S1 for the first strength. /// - public string FactorIdPrefix() => category switch + public string FactorIdPrefix => category switch { SwotAnalysisCategory.STRENGTHS => "S", SwotAnalysisCategory.WEAKNESSES => "W", diff --git a/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisModeration.cs b/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisModeration.cs index c37661f2d..95ca570e8 100644 --- a/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisModeration.cs +++ b/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisModeration.cs @@ -78,8 +78,8 @@ internal static class SwotAnalysisModeration string sharedResearch = "") { var payload = Enum.GetValues().ToDictionary( - category => category.JsonName(), - category => CreateCategoryPayload(categories[category], category.FactorIdPrefix())); + category => category.JsonName, + category => CreateCategoryPayload(categories[category], category.FactorIdPrefix)); return $""" Reconcile these preliminary results of the four SWOT categories. Then write the overall assessment diff --git a/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisModerationResponseParser.cs b/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisModerationResponseParser.cs index 299ba224f..7f806431e 100644 --- a/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisModerationResponseParser.cs +++ b/app/MindWork AI Studio/Assistants/SWOTAnalysis/SwotAnalysisModerationResponseParser.cs @@ -152,12 +152,12 @@ internal static class SwotAnalysisModerationResponseParser /// The first issue, or an empty string. private static string FindIssue(SwotAnalysisCategory category, SwotModeratedCategory moderatedCategory, HashSet factorIds) { - var name = category.JsonName(); + var name = category.JsonName; var listIssue = FindListIssue(name, moderatedCategory.Findings.Count, moderatedCategory.EmptyMessage); if (listIssue.Length > 0) return listIssue; - var prefix = category.FactorIdPrefix(); + var prefix = category.FactorIdPrefix; for (var index = 0; index < moderatedCategory.Findings.Count; index++) { var finding = moderatedCategory.Findings[index]; diff --git a/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceAgeGroupExtensions.cs b/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceAgeGroupExtensions.cs index 0bcf474f1..455cbfa10 100644 --- a/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceAgeGroupExtensions.cs +++ b/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceAgeGroupExtensions.cs @@ -6,7 +6,7 @@ public static class AudienceAgeGroupExtensions extension(AudienceAgeGroup ageGroup) { - public string Name() => ageGroup switch + public string Name => ageGroup switch { AudienceAgeGroup.UNSPECIFIED => TB("Unspecified age group"), AudienceAgeGroup.CHILDREN => TB("Children"), @@ -16,7 +16,7 @@ public static class AudienceAgeGroupExtensions _ => TB("Unspecified age group"), }; - public string Prompt() => ageGroup switch + public string Prompt => ageGroup switch { AudienceAgeGroup.UNSPECIFIED => "Do not tailor the text to a specific age group.", AudienceAgeGroup.CHILDREN => "Use simple, concrete language with short sentences and minimal jargon.", diff --git a/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceExpertiseExtensions.cs b/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceExpertiseExtensions.cs index aab3b907e..1b2715888 100644 --- a/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceExpertiseExtensions.cs +++ b/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceExpertiseExtensions.cs @@ -6,7 +6,7 @@ public static class AudienceExpertiseExtensions extension(AudienceExpertise expertise) { - public string Name() => expertise switch + public string Name => expertise switch { AudienceExpertise.UNSPECIFIED => TB("Unspecified expertise"), AudienceExpertise.NON_EXPERTS => TB("No expertise"), @@ -17,7 +17,7 @@ public static class AudienceExpertiseExtensions _ => TB("Unspecified expertise"), }; - public string Prompt() => expertise switch + public string Prompt => expertise switch { AudienceExpertise.UNSPECIFIED => "Do not tailor the text to a specific expertise level.", AudienceExpertise.NON_EXPERTS => "Avoid jargon and explain specialized concepts plainly.", diff --git a/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceOrganizationalLevelExtensions.cs b/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceOrganizationalLevelExtensions.cs index 685c463e0..4faf0761a 100644 --- a/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceOrganizationalLevelExtensions.cs +++ b/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceOrganizationalLevelExtensions.cs @@ -6,7 +6,7 @@ public static class AudienceOrganizationalLevelExtensions extension(AudienceOrganizationalLevel level) { - public string Name() => level switch + public string Name => level switch { AudienceOrganizationalLevel.UNSPECIFIED => TB("Unspecified organizational level"), AudienceOrganizationalLevel.TRAINEES => TB("Trainees"), @@ -19,7 +19,7 @@ public static class AudienceOrganizationalLevelExtensions _ => TB("Unspecified organizational level"), }; - public string Prompt() => level switch + public string Prompt => level switch { AudienceOrganizationalLevel.UNSPECIFIED => "Do not tailor the text to a specific organizational level.", AudienceOrganizationalLevel.TRAINEES => "Keep the content supportive and introductory. Explain context and avoid assuming prior organizational knowledge.", diff --git a/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceProfileExtensions.cs b/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceProfileExtensions.cs index fe60a70f1..e743998f9 100644 --- a/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceProfileExtensions.cs +++ b/app/MindWork AI Studio/Assistants/SlideBuilder/AudienceProfileExtensions.cs @@ -6,7 +6,7 @@ public static class AudienceProfileExtensions extension(AudienceProfile profile) { - public string Name() => profile switch + public string Name => profile switch { AudienceProfile.UNSPECIFIED => TB("Unspecified audience profile"), AudienceProfile.STUDENTS => TB("Students"), @@ -23,7 +23,7 @@ public static class AudienceProfileExtensions _ => TB("Unspecified audience profile"), }; - public string Prompt() => profile switch + public string Prompt => profile switch { AudienceProfile.UNSPECIFIED => "Do not tailor the text to a specific audience profile.", AudienceProfile.STUDENTS => "Write for students. Keep it structured, easy to study, and focused on key takeaways.", diff --git a/app/MindWork AI Studio/Assistants/SlideBuilder/PresentationOccasionExtensions.cs b/app/MindWork AI Studio/Assistants/SlideBuilder/PresentationOccasionExtensions.cs index e7ee144a0..d167af0b5 100644 --- a/app/MindWork AI Studio/Assistants/SlideBuilder/PresentationOccasionExtensions.cs +++ b/app/MindWork AI Studio/Assistants/SlideBuilder/PresentationOccasionExtensions.cs @@ -7,7 +7,7 @@ public static class PresentationOccasionExtensions /// The occasion. extension(PresentationOccasion occasion) { - public string Name() => occasion switch + public string Name => occasion switch { PresentationOccasion.UNSPECIFIED => TB("Unspecified occasion"), PresentationOccasion.TALK => TB("Talk"), diff --git a/app/MindWork AI Studio/Assistants/SlideBuilder/SlideAssistant.razor b/app/MindWork AI Studio/Assistants/SlideBuilder/SlideAssistant.razor index 9c51c7243..c0260ec55 100644 --- a/app/MindWork AI Studio/Assistants/SlideBuilder/SlideAssistant.razor +++ b/app/MindWork AI Studio/Assistants/SlideBuilder/SlideAssistant.razor @@ -95,22 +95,22 @@ @T("Language") - + @T("Occasion") @T("The occasion helps the LLM to structure the presentation. A lecture, for example, may close its chapters with an interim summary or with room for questions, and a report to management leads with the key messages.") - + @T("Audience") @T("Please specify the audience for the planned presentation. This will help the LLM to create a presentation that fits your needs. You can specify the audience profile, the age group, organizational level, and the expertise. You don't have to specify all of these parameters, for example you might only want to specify the audience profile and leave the other parameters at their default values.") - - - - + + + + @T("PowerPoint template") @@ -160,7 +160,7 @@ - + @LayoutPurposeExtensions.NoPreference @foreach (var layoutName in loadedTemplate.FamilyNames) { @@ -178,7 +178,7 @@ @foreach (var templateSlide in loadedTemplate.Slides) { - + } } diff --git a/app/MindWork AI Studio/Assistants/SlideBuilder/SlideAssistant.razor.cs b/app/MindWork AI Studio/Assistants/SlideBuilder/SlideAssistant.razor.cs index 668df1e9b..e6e3e3293 100644 --- a/app/MindWork AI Studio/Assistants/SlideBuilder/SlideAssistant.razor.cs +++ b/app/MindWork AI Studio/Assistants/SlideBuilder/SlideAssistant.razor.cs @@ -491,16 +491,16 @@ public partial class SlideAssistant : AssistantBaseCore(); if (this.selectedAudienceProfile is not AudienceProfile.UNSPECIFIED) - prompts.Add(this.selectedAudienceProfile.Prompt()); + prompts.Add(this.selectedAudienceProfile.Prompt); if (this.selectedAudienceAgeGroup is not AudienceAgeGroup.UNSPECIFIED) - prompts.Add(this.selectedAudienceAgeGroup.Prompt()); + prompts.Add(this.selectedAudienceAgeGroup.Prompt); if (this.selectedAudienceOrganizationalLevel is not AudienceOrganizationalLevel.UNSPECIFIED) - prompts.Add(this.selectedAudienceOrganizationalLevel.Prompt()); + prompts.Add(this.selectedAudienceOrganizationalLevel.Prompt); if (this.selectedAudienceExpertise is not AudienceExpertise.UNSPECIFIED) - prompts.Add(this.selectedAudienceExpertise.Prompt()); + prompts.Add(this.selectedAudienceExpertise.Prompt); if (prompts.Count == 0) return " - Do not tailor the text to a specific audience."; diff --git a/app/MindWork AI Studio/Assistants/SlideBuilder/TemplateSlideExtensions.cs b/app/MindWork AI Studio/Assistants/SlideBuilder/TemplateSlideExtensions.cs index d5974b9e8..018670989 100644 --- a/app/MindWork AI Studio/Assistants/SlideBuilder/TemplateSlideExtensions.cs +++ b/app/MindWork AI Studio/Assistants/SlideBuilder/TemplateSlideExtensions.cs @@ -20,14 +20,17 @@ internal static class TemplateSlideExtensions /// The title tells the slides apart at a glance, since a template rarely gives its slides more /// than a title. A long one is cut, so that the label stays on one line. /// - public string Label() + public string Label { - var title = slide.Title.Length > MAX_SLIDE_TITLE_CHARACTERS ? $"{slide.Title[..MAX_SLIDE_TITLE_CHARACTERS].TrimEnd()}…" : slide.Title; - var label = title.Length > 0 ? string.Format(TB("Slide {0}: {1}"), slide.Number, title) : string.Format(TB("Slide {0}"), slide.Number); - if (slide.IsHidden) - label = $"{label} ({TB("hidden")})"; + get + { + var title = slide.Title.Length > MAX_SLIDE_TITLE_CHARACTERS ? $"{slide.Title[..MAX_SLIDE_TITLE_CHARACTERS].TrimEnd()}…" : slide.Title; + var label = title.Length > 0 ? string.Format(TB("Slide {0}: {1}"), slide.Number, title) : string.Format(TB("Slide {0}"), slide.Number); + if (slide.IsHidden) + label = $"{label} ({TB("hidden")})"; - return label; + return label; + } } } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/SlideBuilder/TemplateSlideUseExtensions.cs b/app/MindWork AI Studio/Assistants/SlideBuilder/TemplateSlideUseExtensions.cs index aa8d56f1a..786ea058a 100644 --- a/app/MindWork AI Studio/Assistants/SlideBuilder/TemplateSlideUseExtensions.cs +++ b/app/MindWork AI Studio/Assistants/SlideBuilder/TemplateSlideUseExtensions.cs @@ -8,7 +8,7 @@ internal static class TemplateSlideUseExtensions extension(TemplateSlideUse use) { - public string Name() => use switch + public string Name => use switch { TemplateSlideUse.OMIT => TB("Leave out"), TemplateSlideUse.KEEP => TB("Keep unchanged"), diff --git a/app/MindWork AI Studio/Assistants/Synonym/AssistantSynonyms.razor b/app/MindWork AI Studio/Assistants/Synonym/AssistantSynonyms.razor index a9af6c100..7f9cebceb 100644 --- a/app/MindWork AI Studio/Assistants/Synonym/AssistantSynonyms.razor +++ b/app/MindWork AI Studio/Assistants/Synonym/AssistantSynonyms.razor @@ -4,5 +4,5 @@ - + diff --git a/app/MindWork AI Studio/Assistants/Synonym/AssistantSynonyms.razor.cs b/app/MindWork AI Studio/Assistants/Synonym/AssistantSynonyms.razor.cs index 0932118e2..bffcd7c70 100644 --- a/app/MindWork AI Studio/Assistants/Synonym/AssistantSynonyms.razor.cs +++ b/app/MindWork AI Studio/Assistants/Synonym/AssistantSynonyms.razor.cs @@ -157,7 +157,7 @@ public partial class AssistantSynonyms : AssistantBaseCore "source", CommonLanguages.OTHER => this.customTargetLanguage, - _ => $"{this.selectedLanguage.Name()}", + _ => $"{this.selectedLanguage.Name}", }; if (string.IsNullOrWhiteSpace(lang)) diff --git a/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor b/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor index 3b2d0b094..12d2534bd 100644 --- a/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor +++ b/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor @@ -8,7 +8,7 @@ - - + + \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/TextSummarizer/ComplexityExtensions.cs b/app/MindWork AI Studio/Assistants/TextSummarizer/ComplexityExtensions.cs index bc3ab983d..c37b657cc 100644 --- a/app/MindWork AI Studio/Assistants/TextSummarizer/ComplexityExtensions.cs +++ b/app/MindWork AI Studio/Assistants/TextSummarizer/ComplexityExtensions.cs @@ -6,7 +6,7 @@ public static class ComplexityExtensions extension(Complexity complexity) { - public string Name() => complexity switch + public string Name => complexity switch { Complexity.NO_CHANGE => TB("No change in complexity"), diff --git a/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor b/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor index 469358f8f..c864ac47d 100644 --- a/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor +++ b/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor @@ -18,5 +18,5 @@ else } - + \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor.cs b/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor.cs index c042f07ad..b1de7ebaf 100644 --- a/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor.cs +++ b/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor.cs @@ -39,7 +39,7 @@ public partial class AssistantTranslation : AssistantBaseCore $""" - {string.Format(T("Translate the following text to {0}:"), this.selectedTargetLanguage is CommonLanguages.OTHER ? this.customTargetLanguage : this.selectedTargetLanguage.Name())} + {string.Format(T("Translate the following text to {0}:"), this.selectedTargetLanguage is CommonLanguages.OTHER ? this.customTargetLanguage : this.selectedTargetLanguage.Name)} {this.inputText} """; diff --git a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor index 6802e1184..bd8a3cd80 100644 --- a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor +++ b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor @@ -215,11 +215,11 @@ - - - - - + + + + + @T("Show source references") @T("Optimize large visual assets") diff --git a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor.cs b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor.cs index 2389a90ae..42d9b5cad 100644 --- a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor.cs +++ b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor.cs @@ -147,7 +147,7 @@ public partial class VisualBriefingAssistant : MSGComponentBase if (!this.SettingsManager.IsAssistantVisible( ComponentKind.VISUAL_BRIEFING_ASSISTANT, assistantName: T("Visual Briefing Assistant"), - requiredPreviewFeature: ComponentKind.VISUAL_BRIEFING_ASSISTANT.RequiredPreviewFeature())) + requiredPreviewFeature: ComponentKind.VISUAL_BRIEFING_ASSISTANT.RequiredPreviewFeature)) { this.NavigationManager.NavigateTo(Routes.ASSISTANTS); return; diff --git a/app/MindWork AI Studio/Chat/ChatRoleExtensions.cs b/app/MindWork AI Studio/Chat/ChatRoleExtensions.cs index 37c968c9e..0fb0683cb 100644 --- a/app/MindWork AI Studio/Chat/ChatRoleExtensions.cs +++ b/app/MindWork AI Studio/Chat/ChatRoleExtensions.cs @@ -12,8 +12,8 @@ public static class ChatRoleExtensions /// /// Returns the name of the role. /// - /// The name of the role. - public string ToName() => role switch + /// The name of the role. + public string Name => role switch { ChatRole.SYSTEM => TB("System"), ChatRole.USER => TB("You"), @@ -25,8 +25,8 @@ public static class ChatRoleExtensions /// /// Returns the color of the role. /// - /// The color of the role. - public Color ToColor() => role switch + /// The color of the role. + public Color Color => role switch { ChatRole.SYSTEM => Color.Info, ChatRole.USER => Color.Primary, @@ -38,8 +38,8 @@ public static class ChatRoleExtensions /// /// Returns the icon of the role. /// - /// The icon of the role. - public string ToIcon() => role switch + /// The icon of the role. + public string Icon => role switch { ChatRole.SYSTEM => Icons.Material.Filled.Settings, ChatRole.USER => Icons.Material.Filled.Person, @@ -51,8 +51,8 @@ public static class ChatRoleExtensions /// /// Returns the specific name of the role for the chat template. /// - /// The name of the role. - public string ToChatTemplateName() => role switch + /// The name of the role. + public string ChatTemplateName => role switch { ChatRole.SYSTEM => TB("System"), ChatRole.USER => TB("User"), diff --git a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor index 903f9ca9d..a182e195b 100644 --- a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor +++ b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor @@ -6,14 +6,14 @@ - - + + - @this.Role.ToName() (@this.Time.LocalDateTime) + @this.Role.Name (@this.Time.LocalDateTime) @if (this.HasToolTrace) { @@ -87,9 +87,9 @@ { - @foreach (var documentFormat in FileExportFormatExtensions.DOCUMENT_FORMATS) + @foreach (var documentFormat in FileExportFormat.DocumentFormats) { - + } @if (this.MessageFiles.Count > MAX_FILES_WITHOUT_SUBMENUS) { @@ -113,9 +113,9 @@ } } - @foreach (var textFormat in FileExportFormatExtensions.TEXT_FORMATS) + @foreach (var textFormat in FileExportFormat.TextFormats) { - + } @@ -126,7 +126,7 @@ @foreach (var destination in this.SendToDestinations) { - + } diff --git a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs index 21b1b38d9..b430cd022 100644 --- a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs +++ b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs @@ -274,8 +274,8 @@ public partial class ContentBlockComponent : MSGComponentBase /// private string ExportLabel(MessageFile file) { - var isTable = file.Format.IsTabular(); - var filesOfItsKind = this.MessageFiles.Where(entry => entry.Format.IsTabular() == isTable).ToList(); + var isTable = file.Format.IsTabular; + var filesOfItsKind = this.MessageFiles.Where(entry => entry.Format.IsTabular == isTable).ToList(); var extensionOrName = file.ToFileExtensionOrName(); var typeName = file.ToName(); @@ -308,7 +308,7 @@ public partial class ContentBlockComponent : MSGComponentBase /// for the entire answer out of sight. Each submenu keeps the order of the answer, so "Code /// block 3" is the third entry of its submenu as well. /// - private IEnumerable> MessageFilesByKind => this.MessageFiles.GroupBy(file => file.Format.IsTabular()).OrderByDescending(isTable => isTable.Key); + private IEnumerable> MessageFilesByKind => this.MessageFiles.GroupBy(file => file.Format.IsTabular).OrderByDescending(isTable => isTable.Key); /// /// Names the submenu of one kind of files in the export menu, with the number of its files. @@ -322,7 +322,7 @@ public partial class ContentBlockComponent : MSGComponentBase /// /// Returns the icon of the submenu of one kind of files in the export menu. /// - private static string ExportGroupIcon(IGrouping filesOfAKind) => filesOfAKind.Key ? FileExportFormat.CSV.ToIcon() : FileExportFormat.SOURCE_CODE.ToIcon(); + private static string ExportGroupIcon(IGrouping filesOfAKind) => filesOfAKind.Key ? FileExportFormat.CSV.Icon : FileExportFormat.SOURCE_CODE.Icon; /// /// What the export offers, falling back to the chat wording when nobody named it. @@ -649,7 +649,7 @@ public partial class ContentBlockComponent : MSGComponentBase // here which would fall out of sync with the one in FileExportFormatExtensions. // var disclosureService = this.GetsAIGeneratedContentDisclosure ? this.DisclosureService : null; - if (format.UsesPandoc()) + if (format.UsesPandoc) await PandocExport.ToDocument(this.RustService, this.PandocAvailability, disclosureService, this.EffectiveExportTitle, format, this.Content, this.ExportFileName); else if (this.Content.TryGetExportMarkdown(out var markdown)) await PlainFileExport.ToFile(this.RustService, this.EffectiveExportTitle, format, disclosureService?.AddDisclosureToMarkdown(markdown) ?? markdown, this.ExportFileName); diff --git a/app/MindWork AI Studio/Chat/ContentText.cs b/app/MindWork AI Studio/Chat/ContentText.cs index 297c7ae5f..fe3181023 100644 --- a/app/MindWork AI Studio/Chat/ContentText.cs +++ b/app/MindWork AI Studio/Chat/ContentText.cs @@ -127,7 +127,7 @@ public sealed class ContentText : IContent try { // Most answers, those of the agents among them, received nothing to store, and need no database: - if (!this.SourcePassages.Any(passage => passage.HoldsTextsToStore())) + if (!this.SourcePassages.Any(passage => passage.HoldsTextsToStore)) return; if (await ChatProvenance.GetStoreAsync() is { } store && await this.StoreReceivedContentAsync(store, chatId)) @@ -158,7 +158,7 @@ public sealed class ContentText : IContent var passages = new List(this.SourcePassages.Count); foreach (var passage in this.SourcePassages) { - if (!passage.HoldsTextsToStore()) + if (!passage.HoldsTextsToStore) { passages.Add(passage); continue; @@ -168,7 +168,7 @@ public sealed class ContentText : IContent try { // Not cancellable: the answer is complete, also when the user stopped it. - provenanceId = await store.StoreAsync(chatId, passage.GetProvenanceKind(), passage.Text, passage.SurroundingContent, CancellationToken.None); + provenanceId = await store.StoreAsync(chatId, passage.ProvenanceKind, passage.Text, passage.SurroundingContent, CancellationToken.None); } catch (Exception exception) { diff --git a/app/MindWork AI Studio/Chat/IContentExtensions.cs b/app/MindWork AI Studio/Chat/IContentExtensions.cs index 6c09a6302..7a124600c 100644 --- a/app/MindWork AI Studio/Chat/IContentExtensions.cs +++ b/app/MindWork AI Studio/Chat/IContentExtensions.cs @@ -95,13 +95,13 @@ public static class IContentExtensions /// The content of the file to write. public string ToExportContent(MessageFile file) { - if (file.Format.IsTabular()) + if (file.Format.IsTabular) return file.Content; if (file.Format is FileExportFormat.SOURCE_CODE) return ToSourceCodeFile(file); - var sources = content.Sources.ToExportMarkdown(file.Format.FollowsPageAnchors()); + var sources = content.Sources.ToExportMarkdown(file.Format.FollowsPageAnchors); if (file.Format is FileExportFormat.MARKDOWN) return AppendSources(file.Content, sources); diff --git a/app/MindWork AI Studio/Chat/IImageSourceExtensions.cs b/app/MindWork AI Studio/Chat/IImageSourceExtensions.cs index d065ea00c..6d656f0f4 100644 --- a/app/MindWork AI Studio/Chat/IImageSourceExtensions.cs +++ b/app/MindWork AI Studio/Chat/IImageSourceExtensions.cs @@ -25,8 +25,8 @@ public static class IImageSourceExtensions /// The size limit of one image file. public static long MaxImageSizeBytesFor(AIStudio.Settings.Provider provider) { - var engineLimit = provider.UsedLLMProvider is LLMProviders.SELF_HOSTED ? provider.Host.GetMaxImageSizeBytes() : null; - var providerLimit = provider.UsedLLMProvider.GetMaxImageSizeBytes(); + var engineLimit = provider.UsedLLMProvider is LLMProviders.SELF_HOSTED ? provider.Host.MaxImageSizeBytes : null; + var providerLimit = provider.UsedLLMProvider.MaxImageSizeBytes; return Math.Min(Math.Min(engineLimit ?? MAX_IMAGE_SIZE_BYTES, providerLimit ?? MAX_IMAGE_SIZE_BYTES), MAX_IMAGE_SIZE_BYTES); } diff --git a/app/MindWork AI Studio/Components/AssistantBlock.razor.cs b/app/MindWork AI Studio/Components/AssistantBlock.razor.cs index 8b7ef9371..dc170b914 100644 --- a/app/MindWork AI Studio/Components/AssistantBlock.razor.cs +++ b/app/MindWork AI Studio/Components/AssistantBlock.razor.cs @@ -125,8 +125,8 @@ public partial class AssistantBlock : MSGComponentBase, IAssistantCat /// true when this block represents the owner. private bool OwnedByThisBlock(MediaImportOwner owner) { - if (owner.Kind.PersistsOwnSources()) - return owner.Kind == this.Component.MediaOwnerKind(); + if (owner.Kind.PersistsOwnSources) + return owner.Kind == this.Component.MediaOwnerKind; if (string.IsNullOrWhiteSpace(this.AssistantSessionInstanceId)) return owner.Kind is MediaImportOwnerKind.ASSISTANT && owner.Id.StartsWith($"{this.Component}:", StringComparison.Ordinal); diff --git a/app/MindWork AI Studio/Components/AssistantPluginSecurityCard.razor b/app/MindWork AI Studio/Components/AssistantPluginSecurityCard.razor index 7a6ff20b4..59a9d71b9 100644 --- a/app/MindWork AI Studio/Components/AssistantPluginSecurityCard.razor +++ b/app/MindWork AI Studio/Components/AssistantPluginSecurityCard.razor @@ -256,7 +256,7 @@ @T("Required minimum") - @state.Settings.MinimumLevel.GetName() + @state.Settings.MinimumLevel.Name @@ -290,7 +290,7 @@ @foreach (var finding in state.Audit.Findings) { - + @finding.Category: @finding.Description @if (!string.IsNullOrWhiteSpace(finding.Location)) { diff --git a/app/MindWork AI Studio/Components/AttachDocuments.razor.cs b/app/MindWork AI Studio/Components/AttachDocuments.razor.cs index ebde89830..571009793 100644 --- a/app/MindWork AI Studio/Components/AttachDocuments.razor.cs +++ b/app/MindWork AI Studio/Components/AttachDocuments.razor.cs @@ -185,7 +185,7 @@ public partial class AttachDocuments : MSGComponentBase var delivery = this.MediaTranscriptionService.GetPendingDelivery(this.EffectiveMediaImportTarget); // Owners that persist their own sources have already taken the media over when the batch // started, so re-adding the delivered transcripts here would duplicate them. - var completed = this.EffectiveImportOwner.Kind.PersistsOwnSources() + var completed = this.EffectiveImportOwner.Kind.PersistsOwnSources ? Array.Empty() : delivery?.Attachments ?? []; var pending = this.OwnerChat?.Draft.MediaTranscripts ?? []; @@ -436,7 +436,7 @@ public partial class AttachDocuments : MSGComponentBase // Owners that persist their own sources show the file right away and keep it next to the // stored document, instead of waiting for the transcription to be delivered back. - if (this.EffectiveImportOwner.Kind.PersistsOwnSources()) + if (this.EffectiveImportOwner.Kind.PersistsOwnSources) { foreach (var mediaPath in mediaPaths) this.DocumentPaths.Add(FileAttachment.FromPath(mediaPath)); diff --git a/app/MindWork AI Studio/Components/ChatComponent.razor.cs b/app/MindWork AI Studio/Components/ChatComponent.razor.cs index 88b373232..c08c655f9 100644 --- a/app/MindWork AI Studio/Components/ChatComponent.razor.cs +++ b/app/MindWork AI Studio/Components/ChatComponent.razor.cs @@ -795,7 +795,7 @@ public partial class ChatComponent : MSGComponentBase get { if (this.IsProviderSelected) - return string.Format(T("Your Prompt (use selected instance '{0}', provider '{1}')"), this.Provider.InstanceName, this.Provider.UsedLLMProvider.ToName()); + return string.Format(T("Your Prompt (use selected instance '{0}', provider '{1}')"), this.Provider.InstanceName, this.Provider.UsedLLMProvider.Name); return this.T("Select a provider first"); } diff --git a/app/MindWork AI Studio/Components/ConfidenceInfo.razor b/app/MindWork AI Studio/Components/ConfidenceInfo.razor index 95980fd38..381dafe28 100644 --- a/app/MindWork AI Studio/Components/ConfidenceInfo.razor +++ b/app/MindWork AI Studio/Components/ConfidenceInfo.razor @@ -48,7 +48,7 @@ @T("Confidence Level") - @this.currentConfidence.Level.GetName() + @this.currentConfidence.Level.Name diff --git a/app/MindWork AI Studio/Components/DataSourceManagement.razor b/app/MindWork AI Studio/Components/DataSourceManagement.razor index 40d7a7e3c..2d7fea481 100644 --- a/app/MindWork AI Studio/Components/DataSourceManagement.razor +++ b/app/MindWork AI Studio/Components/DataSourceManagement.razor @@ -58,7 +58,7 @@
@context.Name
- @context.Type.GetDisplayName() + @context.Type.DisplayName @this.GetEmbeddingName(context) @if (context is IIndexedDataSource) diff --git a/app/MindWork AI Studio/Components/DataSourceManagement.razor.cs b/app/MindWork AI Studio/Components/DataSourceManagement.razor.cs index 16b1c2922..19046729b 100644 --- a/app/MindWork AI Studio/Components/DataSourceManagement.razor.cs +++ b/app/MindWork AI Studio/Components/DataSourceManagement.razor.cs @@ -306,7 +306,7 @@ public partial class DataSourceManagement : MSGComponentBase var dialogParameters = new DialogParameters { - { x => x.Message, string.Format(T("Are you sure you want to delete the data source '{0}' of type '{1}'?"), dataSource.Name, dataSource.Type.GetDisplayName()) }, + { x => x.Message, string.Format(T("Are you sure you want to delete the data source '{0}' of type '{1}'?"), dataSource.Name, dataSource.Type.DisplayName) }, }; var dialogReference = await this.DialogService.ShowAsync(T("Delete Data Source"), dialogParameters, DialogOptions.FULLSCREEN); diff --git a/app/MindWork AI Studio/Components/DataSourceSelection.razor b/app/MindWork AI Studio/Components/DataSourceSelection.razor index 3717e3807..9d851122b 100644 --- a/app/MindWork AI Studio/Components/DataSourceSelection.razor +++ b/app/MindWork AI Studio/Components/DataSourceSelection.razor @@ -146,7 +146,7 @@ @if (source.DataSource is IInternalDataSource internalSource) { - + } diff --git a/app/MindWork AI Studio/Components/DataSourceSelectionRow.razor b/app/MindWork AI Studio/Components/DataSourceSelectionRow.razor index d31184fc4..03f81ee57 100644 --- a/app/MindWork AI Studio/Components/DataSourceSelectionRow.razor +++ b/app/MindWork AI Studio/Components/DataSourceSelectionRow.razor @@ -15,7 +15,7 @@ { } - + } diff --git a/app/MindWork AI Studio/Components/HighlightedCodeBlock.cs b/app/MindWork AI Studio/Components/HighlightedCodeBlock.cs index 75c0786ea..f6a09140d 100644 --- a/app/MindWork AI Studio/Components/HighlightedCodeBlock.cs +++ b/app/MindWork AI Studio/Components/HighlightedCodeBlock.cs @@ -66,7 +66,7 @@ public sealed class HighlightedCodeBlock : ComponentBase builder.AddContent(2, this.Code[position..token.Start]); builder.OpenElement(3, "span"); - builder.AddAttribute(4, "class", token.Kind.ToCssClass()); + builder.AddAttribute(4, "class", token.Kind.CssClass); builder.AddContent(5, this.Code.Substring(token.Start, token.Length)); builder.CloseElement(); position = token.Start + token.Length; diff --git a/app/MindWork AI Studio/Components/LayoutChoicePanels.razor b/app/MindWork AI Studio/Components/LayoutChoicePanels.razor index ea7bf3e33..bf7bc2221 100644 --- a/app/MindWork AI Studio/Components/LayoutChoicePanels.razor +++ b/app/MindWork AI Studio/Components/LayoutChoicePanels.razor @@ -4,7 +4,7 @@ @if (this.expandedAreas.Contains(area)) { - @foreach (var purpose in Enum.GetValues().Where(purpose => purpose.Area() == area)) + @foreach (var purpose in Enum.GetValues().Where(purpose => purpose.Area == area)) { @this.ChoiceContent(purpose) } diff --git a/app/MindWork AI Studio/Components/LayoutChoicePanels.razor.cs b/app/MindWork AI Studio/Components/LayoutChoicePanels.razor.cs index cc52da377..244da170f 100644 --- a/app/MindWork AI Studio/Components/LayoutChoicePanels.razor.cs +++ b/app/MindWork AI Studio/Components/LayoutChoicePanels.razor.cs @@ -35,8 +35,8 @@ public partial class LayoutChoicePanels : ComponentBase private string HeaderTextOf(LayoutPurposeArea area) { - var chosen = Enum.GetValues().Count(purpose => purpose.Area() == area && this.IsChosen(purpose)); - return chosen == 0 ? area.Label() : $"{area.Label()} ({chosen})"; + var chosen = Enum.GetValues().Count(purpose => purpose.Area == area && this.IsChosen(purpose)); + return chosen == 0 ? area.Label : $"{area.Label} ({chosen})"; } private void SetExpanded(LayoutPurposeArea area, bool expanded) diff --git a/app/MindWork AI Studio/Components/OutboundDataRestrictionSelection.razor b/app/MindWork AI Studio/Components/OutboundDataRestrictionSelection.razor index 4150f009c..dafab3a42 100644 --- a/app/MindWork AI Studio/Components/OutboundDataRestrictionSelection.razor +++ b/app/MindWork AI Studio/Components/OutboundDataRestrictionSelection.razor @@ -2,7 +2,7 @@ @using AIStudio.Settings.DataModel @inherits MSGComponentBase - + @foreach (var restriction in ConfigurationSelectDataFactory.GetOutboundDataRestrictionData(this.Minimum)) { @@ -11,7 +11,7 @@ } - @this.Value.GetDescription() + @this.Value.Description @if (this.LimitationText is { } limitationText) { diff --git a/app/MindWork AI Studio/Components/ReadWebContentStepsExtensions.cs b/app/MindWork AI Studio/Components/ReadWebContentStepsExtensions.cs index 419cfb37e..39fa149c4 100644 --- a/app/MindWork AI Studio/Components/ReadWebContentStepsExtensions.cs +++ b/app/MindWork AI Studio/Components/ReadWebContentStepsExtensions.cs @@ -12,8 +12,8 @@ public static class ReadWebContentStepsExtensions /// /// Gets the text representation of a given ReadWebContentSteps enum value. /// - /// >The text representation of the process step. - public string GetText() => step switch + /// The text representation of the process step. + public string Text => step switch { ReadWebContentSteps.START => TB("Start"), ReadWebContentSteps.LOADING => TB("Loading"), diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor.cs index 4dd638c7b..a4fc2beb7 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelApp.razor.cs @@ -128,14 +128,14 @@ public partial class SettingsPanelApp : SettingsPanelBase // Several configuration plugins may contribute at the same time, e.g. one preview feature // for the whole organization and another one for a single department: if (ManagedConfiguration.TryGet(x => x.App, x => x.EnabledPreviewFeatures, out var meta) && meta.HasPluginContribution) - return meta.PluginContributions.Values.SelectMany(contribution => contribution).Where(x => !x.IsReleased()).ToHashSet(); + return meta.PluginContributions.Values.SelectMany(contribution => contribution).Where(x => !x.IsReleased).ToHashSet(); return []; } private bool IsPluginContributedPreviewFeature(PreviewFeatures feature) { - if (feature.IsReleased()) + if (feature.IsReleased) return false; if (!ManagedConfiguration.TryGet(x => x.App, x => x.EnabledPreviewFeatures, out var meta) || !meta.HasPluginContribution) @@ -146,7 +146,7 @@ public partial class SettingsPanelApp : SettingsPanelBase private HashSet GetSelectedPreviewFeatures() { - var enabled = this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures.Where(x => !x.IsReleased()).ToHashSet(); + var enabled = this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures.Where(x => !x.IsReleased).ToHashSet(); enabled.UnionWith(this.GetPluginContributedPreviewFeatures()); return enabled; } diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelConfidence.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelConfidence.razor index c2bbff809..b1311e156 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelConfidence.razor +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelConfidence.razor @@ -35,7 +35,7 @@ - @context.ToName() + @context.Name @@ -54,7 +54,7 @@ continue; - @confidenceLevel.GetName() + @confidenceLevel.Name } diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelConfidence.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelConfidence.razor.cs index ec3674a22..b416ec6ce 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelConfidence.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelConfidence.razor.cs @@ -8,7 +8,7 @@ public partial class SettingsPanelConfidence : SettingsPanelBase private string GetCurrentConfidenceLevelName(LLMProviders llmProvider) { if (this.TryGetShownConfidenceLevel(llmProvider, out var level)) - return level.GetName(); + return level.Name; return T("Not yet configured"); } diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor index e7a8c8546..792462a98 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor @@ -32,7 +32,7 @@ @if (context.Key is LLMProviders llmProvider) { - + } @@ -74,7 +74,7 @@ else { - + diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor index 86343dd01..313baa4d9 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor @@ -25,7 +25,7 @@ @if (context.Key is LLMProviders llmProvider) { - + } @@ -63,7 +63,7 @@ else { - + diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelTools.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelTools.razor.cs index 0acbeea6a..06235b98b 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelTools.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelTools.razor.cs @@ -107,7 +107,7 @@ public partial class SettingsPanelTools : SettingsPanelBase // minimum confidence; the long wording wraps into a tall block there: private string GetConfidenceLevelName(ConfidenceLevel confidenceLevel) => confidenceLevel is ConfidenceLevel.NONE ? this.T("No minimum") - : confidenceLevel.GetName(); + : confidenceLevel.Name; private string SetCurrentConfidenceLevelColorStyle(ToolCatalogItem item) => $"background-color: {GetMinimumProviderConfidence(item).GetColor(this.SettingsManager)};"; diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor index 537660009..b1f841e08 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor @@ -29,7 +29,7 @@ @if (context.Key is LLMProviders llmProvider) { - + } @@ -68,7 +68,7 @@ else { - + diff --git a/app/MindWork AI Studio/Components/SourcePassageView.razor.cs b/app/MindWork AI Studio/Components/SourcePassageView.razor.cs index 22c906129..5904a9d3d 100644 --- a/app/MindWork AI Studio/Components/SourcePassageView.razor.cs +++ b/app/MindWork AI Studio/Components/SourcePassageView.razor.cs @@ -187,7 +187,7 @@ public partial class SourcePassageView : MSGComponentBase /// private string GetTranscriptLabel() { - if (!this.Passage.IsTranscript()) + if (!this.Passage.IsTranscript) return string.Empty; var extension = Path.GetExtension(this.Passage.Path); diff --git a/app/MindWork AI Studio/Components/ToolSelection.razor.cs b/app/MindWork AI Studio/Components/ToolSelection.razor.cs index b8d9a9c04..74d8f6034 100644 --- a/app/MindWork AI Studio/Components/ToolSelection.razor.cs +++ b/app/MindWork AI Studio/Components/ToolSelection.razor.cs @@ -194,8 +194,8 @@ public partial class ToolSelection : MSGComponentBase return string.Format( this.T("This tool requires provider confidence {0}. The selected provider has {1}."), - GetMinimumProviderConfidence(item).GetName(), - this.ProviderConfidence.GetName()); + GetMinimumProviderConfidence(item).Name, + this.ProviderConfidence.Name); } /// diff --git a/app/MindWork AI Studio/Dialogs/AssistantPluginAuditDialog.razor b/app/MindWork AI Studio/Dialogs/AssistantPluginAuditDialog.razor index 2fd23fc0a..c08f5b260 100644 --- a/app/MindWork AI Studio/Dialogs/AssistantPluginAuditDialog.razor +++ b/app/MindWork AI Studio/Dialogs/AssistantPluginAuditDialog.razor @@ -219,7 +219,7 @@ else { - @this.audit.Level.GetName(): @this.audit.Summary + @this.audit.Level.Name: @this.audit.Summary @if (this.IsActivationBlockedBySettings) @@ -277,7 +277,7 @@ @finding.Category - @finding.Severity.GetName() + @finding.Severity.Name @finding.Location @finding.Description diff --git a/app/MindWork AI Studio/Dialogs/AssistantPluginAuditDialog.razor.cs b/app/MindWork AI Studio/Dialogs/AssistantPluginAuditDialog.razor.cs index 88af50046..d8f45086e 100644 --- a/app/MindWork AI Studio/Dialogs/AssistantPluginAuditDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/AssistantPluginAuditDialog.razor.cs @@ -64,13 +64,13 @@ public partial class AssistantPluginAuditDialog : MSGComponentBase private string ProviderLabel => this.EffectiveProvider == AIStudio.Settings.Provider.NONE ? T("No model configured") - : $"{this.EffectiveProvider.InstanceName} ({this.EffectiveProvider.UsedLLMProvider.ToName()})"; + : $"{this.EffectiveProvider.InstanceName} ({this.EffectiveProvider.UsedLLMProvider.Name})"; private DataAssistantPluginAudit AuditSettings => this.SettingsManager.ConfigurationData.AssistantPluginAudit; private AssistantAuditLevel MinimumLevel => this.SettingsManager.ConfigurationData.AssistantPluginAudit.MinimumLevel; - private string MinimumLevelLabel => this.MinimumLevel.GetName(); + private string MinimumLevelLabel => this.MinimumLevel.Name; private bool CanRunAudit => this.plugin is not null && this.EffectiveProvider != AIStudio.Settings.Provider.NONE && !this.isAuditing && !this.securityState.IsEnterpriseApproved; @@ -200,7 +200,7 @@ public partial class AssistantPluginAuditDialog : MSGComponentBase string.Format( T("The assistant plugin '{0}' was audited with the level '{1}', which is below the required safety level '{2}'. Your current settings still allow activation, but this may be unsafe. Do you really want to enable this plugin?"), this.plugin?.Name ?? T("Unknown plugin"), - this.audit?.Level.GetName() ?? T("Unknown"), + this.audit?.Level.Name ?? T("Unknown"), this.MinimumLevelLabel) }, }; @@ -254,7 +254,7 @@ public partial class AssistantPluginAuditDialog : MSGComponentBase { Text = this.GetComponentTreeItemText(component), Caption = this.GetComponentTreeItemCaption(component, index), - Icon = component.Type.GetIcon(), + Icon = component.Type.Icon, Expandable = children.Count > 0, }, Children = children, @@ -460,7 +460,7 @@ public partial class AssistantPluginAuditDialog : MSGComponentBase private string GetComponentTreeItemText(IAssistantComponent component) { - var type = component.Type.GetDisplayName(); + var type = component.Type.DisplayName; if (component is INamedAssistantComponent named && !string.IsNullOrWhiteSpace(named.Name)) return $"{type}: {named.Name}"; diff --git a/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor b/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor index c577262e5..8c14ae94e 100644 --- a/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor +++ b/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor @@ -253,7 +253,7 @@ - @context.Role.ToChatTemplateName() + @context.Role.ChatTemplateName @switch(context.Content) @@ -287,7 +287,7 @@ @if (this.IsReadOnly) { - @context.Role.ToChatTemplateName() + @context.Role.ChatTemplateName } else { @@ -295,7 +295,7 @@ @foreach (var role in ChatRoles.ChatTemplateRoles()) { - @role.ToChatTemplateName() + @role.ChatTemplateName } diff --git a/app/MindWork AI Studio/Dialogs/DataSourceERI_V1Dialog.razor b/app/MindWork AI Studio/Dialogs/DataSourceERI_V1Dialog.razor index 74395a9e9..5be0ed1c4 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceERI_V1Dialog.razor +++ b/app/MindWork AI Studio/Dialogs/DataSourceERI_V1Dialog.razor @@ -72,11 +72,11 @@ @if(this.availableAuthMethods.Count > 0 || this.dataAuthMethod != default) { - + @foreach (var authMethod in this.availableAuthMethods) { - @authMethod.DisplayName() + @authMethod.DisplayName } @@ -116,11 +116,11 @@ } - + @foreach (var policy in Enum.GetValues()) { - @policy.ToSelectionText() + @policy.SelectionText } diff --git a/app/MindWork AI Studio/Dialogs/DataSourceERI_V1InfoDialog.razor b/app/MindWork AI Studio/Dialogs/DataSourceERI_V1InfoDialog.razor index a3966f939..846353231 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceERI_V1InfoDialog.razor +++ b/app/MindWork AI Studio/Dialogs/DataSourceERI_V1InfoDialog.razor @@ -25,8 +25,8 @@ } - - + + diff --git a/app/MindWork AI Studio/Dialogs/DataSourceERI_V1InfoDialog.razor.cs b/app/MindWork AI Studio/Dialogs/DataSourceERI_V1InfoDialog.razor.cs index 1b7568422..107874585 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceERI_V1InfoDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/DataSourceERI_V1InfoDialog.razor.cs @@ -56,7 +56,7 @@ public partial class DataSourceERI_V1InfoDialog : MSGComponentBase, ISecretId /// /// The level which applies, including what the organization or the security policy demands. /// - private string OutboundDataRestrictionName => this.DataSource.GetEffectiveOutboundDataRestriction(this.SettingsManager.ConfigurationData.DataSourceSecurity.MinimumOutboundDataRestriction).GetName(); + private string OutboundDataRestrictionName => this.DataSource.GetEffectiveOutboundDataRestriction(this.SettingsManager.ConfigurationData.DataSourceSecurity.MinimumOutboundDataRestriction).Name; private async Task<(bool Success, DataSourceERI_V1 EffectiveDataSource)> CreateEffectiveDataSource() { diff --git a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor index d296eac82..05be158ff 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor +++ b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor @@ -124,7 +124,7 @@ @T("Data sharing") - + @foreach (var level in this.ConfidenceLevels) { diff --git a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryInfoDialog.razor b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryInfoDialog.razor index 340edf6cb..536df567e 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryInfoDialog.razor +++ b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryInfoDialog.razor @@ -43,7 +43,7 @@ } - + diff --git a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryInfoDialog.razor.cs b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryInfoDialog.razor.cs index 36879e4de..6fcabb6d8 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryInfoDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryInfoDialog.razor.cs @@ -65,7 +65,7 @@ public partial class DataSourceLocalDirectoryInfoDialog : MSGComponentBase /// /// The level which applies, including what the organization demands. /// - private string OutboundDataRestrictionName => this.DataSource.GetEffectiveOutboundDataRestriction(this.SettingsManager.ConfigurationData.DataSourceSecurity.MinimumOutboundDataRestriction).GetName(); + private string OutboundDataRestrictionName => this.DataSource.GetEffectiveOutboundDataRestriction(this.SettingsManager.ConfigurationData.DataSourceSecurity.MinimumOutboundDataRestriction).Name; /// /// Takes the next file which the directory scan found. diff --git a/app/MindWork AI Studio/Dialogs/DataSourceLocalFileDialog.razor b/app/MindWork AI Studio/Dialogs/DataSourceLocalFileDialog.razor index bb6b0382a..39e638f80 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceLocalFileDialog.razor +++ b/app/MindWork AI Studio/Dialogs/DataSourceLocalFileDialog.razor @@ -86,7 +86,7 @@ @T("Data sharing") - + @foreach (var level in this.ConfidenceLevels) { diff --git a/app/MindWork AI Studio/Dialogs/DataSourceLocalFileInfoDialog.razor b/app/MindWork AI Studio/Dialogs/DataSourceLocalFileInfoDialog.razor index 34dd0de63..b8cda3fbe 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceLocalFileInfoDialog.razor +++ b/app/MindWork AI Studio/Dialogs/DataSourceLocalFileInfoDialog.razor @@ -37,7 +37,7 @@ } - + diff --git a/app/MindWork AI Studio/Dialogs/DataSourceLocalFileInfoDialog.razor.cs b/app/MindWork AI Studio/Dialogs/DataSourceLocalFileInfoDialog.razor.cs index 8dba0751a..ce1c967c0 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceLocalFileInfoDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/DataSourceLocalFileInfoDialog.razor.cs @@ -37,7 +37,7 @@ public partial class DataSourceLocalFileInfoDialog : MSGComponentBase /// /// The level which applies, including what the organization demands. /// - private string OutboundDataRestrictionName => this.DataSource.GetEffectiveOutboundDataRestriction(this.SettingsManager.ConfigurationData.DataSourceSecurity.MinimumOutboundDataRestriction).GetName(); + private string OutboundDataRestrictionName => this.DataSource.GetEffectiveOutboundDataRestriction(this.SettingsManager.ConfigurationData.DataSourceSecurity.MinimumOutboundDataRestriction).Name; private void Close() => this.MudDialog.Close(); } \ No newline at end of file diff --git a/app/MindWork AI Studio/Dialogs/DataSourceMailboxDialog.razor b/app/MindWork AI Studio/Dialogs/DataSourceMailboxDialog.razor index 541f60f41..705962457 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceMailboxDialog.razor +++ b/app/MindWork AI Studio/Dialogs/DataSourceMailboxDialog.razor @@ -27,7 +27,7 @@ { - @MailboxConnectionFailure.SERVER_NOT_ALLOWED.GetDescription() + @MailboxConnectionFailure.SERVER_NOT_ALLOWED.Description } @@ -164,7 +164,7 @@ } - @string.Format(T("Username: {0}"), this.selectedTemplate.UsernameFormat.GetDescription()) + @string.Format(T("Username: {0}"), this.selectedTemplate.UsernameFormat.Description) @string.Format(T("Instructions of {0}"), this.selectedTemplate.Name) @@ -214,7 +214,7 @@ Variant="Variant.Outlined"/> - + @foreach (var transportSecurity in ConfigurationSelectDataFactory.GetMailboxTransportSecurityData()) { @@ -301,7 +301,7 @@ } - + @foreach (var maxAge in ConfigurationSelectDataFactory.GetMailboxMaxAgeData()) { diff --git a/app/MindWork AI Studio/Dialogs/DataSourceMailboxDialog.razor.cs b/app/MindWork AI Studio/Dialogs/DataSourceMailboxDialog.razor.cs index aa060f2a5..ee31dc21c 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceMailboxDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/DataSourceMailboxDialog.razor.cs @@ -339,7 +339,7 @@ public partial class DataSourceMailboxDialog : MSGComponentBase // Without a root folder, the sent mails and the drafts belong to the whole mailbox anyway: private bool HasRootFolder => !string.IsNullOrEmpty(this.dataRootFolder); - private string ConfidenceLevelText => this.dataConfidenceLevel is ConfidenceLevel.NONE ? string.Empty : this.dataConfidenceLevel.GetName(); + private string ConfidenceLevelText => this.dataConfidenceLevel is ConfidenceLevel.NONE ? string.Empty : this.dataConfidenceLevel.Name; private OutboundDataRestriction MinimumOutboundDataRestriction => this.SettingsManager.ConfigurationData.MailboxSettings.MinimumOutboundDataRestriction; @@ -353,7 +353,7 @@ public partial class DataSourceMailboxDialog : MSGComponentBase if (this.testedSettings != this.CurrentSettings) return this.RequiresConnectionTest ? T("Not tested yet.") : string.Empty; - return this.testFailure is { } failure ? failure.GetDescription() : T("Connection successful."); + return this.testFailure is { } failure ? failure.Description : T("Connection successful."); } } @@ -493,7 +493,7 @@ public partial class DataSourceMailboxDialog : MSGComponentBase // Who switches the encryption usually means the port that comes with it, unless they // entered a port of their own: // - if (this.dataPort == this.dataTransportSecurity.GetUsualPort() && transportSecurity.GetUsualPort() is { } usualPort) + if (this.dataPort == this.dataTransportSecurity.UsualPort && transportSecurity.UsualPort is { } usualPort) this.dataPort = usualPort; this.dataTransportSecurity = transportSecurity; @@ -565,7 +565,7 @@ public partial class DataSourceMailboxDialog : MSGComponentBase serverAnswer = e.InnerException?.Message ?? string.Empty; this.folderIssue = e.Failure is MailboxConnectionFailure.SERVER_ERROR ? T("The server did not create the folder. Perhaps a folder of this name exists already.") - : e.Failure.GetDescription(); + : e.Failure.Description; this.Logger.LogWarning($"Creating a folder in the mailbox '{this.dataId}' failed: {e.Failure} ({e.InnerException?.GetType().Name ?? "no inner exception"})."); return null; @@ -577,7 +577,7 @@ public partial class DataSourceMailboxDialog : MSGComponentBase } catch (OperationCanceledException) { - this.folderIssue = MailboxConnectionFailure.NETWORK_UNAVAILABLE.GetDescription(); + this.folderIssue = MailboxConnectionFailure.NETWORK_UNAVAILABLE.Description; return null; } finally diff --git a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor index 0ed45e073..35a7faf06 100644 --- a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor +++ b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor @@ -17,15 +17,15 @@ @foreach (LLMProviders provider in Enum.GetValues(typeof(LLMProviders))) { - if (provider.ProvideEmbeddingAPI() || provider is LLMProviders.NONE) + if (provider.ProvideEmbeddingAPI || provider is LLMProviders.NONE) { - + } } - + @T("Create account") @@ -43,7 +43,7 @@ } - @if (this.DataLLMProvider.IsHostnameNeeded()) + @if (this.DataLLMProvider.IsHostnameNeeded) { } - @if (this.DataLLMProvider.IsHostNeeded()) + @if (this.DataLLMProvider.IsHostNeeded) { @foreach (Host host in Enum.GetValues(typeof(Host))) { - if (host.IsEmbeddingSupported()) + if (host.IsEmbeddingSupported) { - @host.Name() + @host.Name } } } - @if (this.DataLLMProvider.IsHFInstanceProviderNeeded()) + @if (this.DataLLMProvider.IsHFInstanceProviderNeeded) { @foreach (HFInferenceProvider inferenceProvider in Enum.GetValues(typeof(HFInferenceProvider))) { - @if (inferenceProvider.SupportsEmbeddings()) + @if (inferenceProvider.SupportsEmbeddings) { - @inferenceProvider.ToName() + @inferenceProvider.Name } } diff --git a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs index 11b3c70e6..143f00bbb 100644 --- a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs @@ -285,7 +285,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId // 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 SecretId => this.IsEnterpriseConfiguration ? $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{this.DataLLMProvider.SecretId}" : this.DataLLMProvider.SecretId; public string SecretName => this.DataName; diff --git a/app/MindWork AI Studio/Dialogs/PandocDialog.razor.cs b/app/MindWork AI Studio/Dialogs/PandocDialog.razor.cs index 7f35f6f7b..78628438c 100644 --- a/app/MindWork AI Studio/Dialogs/PandocDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/PandocDialog.razor.cs @@ -9,7 +9,7 @@ namespace AIStudio.Dialogs; public partial class PandocDialog : MSGComponentBase { // Use runtime detection instead of metadata to ensure correct RID on dev machines: - private static readonly RID CPU_ARCHITECTURE = RIDExtensions.GetCurrentRID(); + private static readonly RID CPU_ARCHITECTURE = RID.Current; [Parameter] public bool ShowInstallationPage { get; set; } diff --git a/app/MindWork AI Studio/Dialogs/PluginImportDialog.razor.cs b/app/MindWork AI Studio/Dialogs/PluginImportDialog.razor.cs index 9654a1f7e..785081558 100644 --- a/app/MindWork AI Studio/Dialogs/PluginImportDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/PluginImportDialog.razor.cs @@ -35,7 +35,7 @@ public partial class PluginImportDialog : MSGComponentBase _ => this.T("You are about to install a plugin from a file."), }; - private string TypeLabel => this.Preview.Plugin.Type.GetName(); + private string TypeLabel => this.Preview.Plugin.Type.Name; private string AuthorsLabel => this.Preview.Plugin.Authors.Length > 0 ? string.Join(", ", this.Preview.Plugin.Authors) diff --git a/app/MindWork AI Studio/Dialogs/PluginInfoDialog.razor.cs b/app/MindWork AI Studio/Dialogs/PluginInfoDialog.razor.cs index d711ac161..2e792b7f2 100644 --- a/app/MindWork AI Studio/Dialogs/PluginInfoDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/PluginInfoDialog.razor.cs @@ -26,13 +26,13 @@ public partial class PluginInfoDialog : MSGComponentBase [Parameter] public IAvailablePlugin Plugin { get; set; } = null!; - private string TypeText => this.Plugin.Type.GetName(); + private string TypeText => this.Plugin.Type.Name; private string AuthorsText => this.Plugin.Authors.Length > 0 ? string.Join(", ", this.Plugin.Authors) : this.T("No authors specified"); - private string CategoriesText => this.Plugin.Categories.Length > 0 ? string.Join(", ", this.Plugin.Categories.Select(category => category.GetName())) : this.T("No categories specified"); + private string CategoriesText => this.Plugin.Categories.Length > 0 ? string.Join(", ", this.Plugin.Categories.Select(category => category.Name)) : this.T("No categories specified"); - private string TargetGroupsText => this.Plugin.TargetGroups.Length > 0 ? string.Join(", ", this.Plugin.TargetGroups.Select(targetGroup => targetGroup.Name())) : this.T("No target groups specified"); + private string TargetGroupsText => this.Plugin.TargetGroups.Length > 0 ? string.Join(", ", this.Plugin.TargetGroups.Select(targetGroup => targetGroup.Name)) : this.T("No target groups specified"); /// /// The plugin states the time in UTC; the user reads it in their own time zone. diff --git a/app/MindWork AI Studio/Dialogs/PromptInjectionAlertDialog.razor b/app/MindWork AI Studio/Dialogs/PromptInjectionAlertDialog.razor index c82592bfd..0edf16c2c 100644 --- a/app/MindWork AI Studio/Dialogs/PromptInjectionAlertDialog.razor +++ b/app/MindWork AI Studio/Dialogs/PromptInjectionAlertDialog.razor @@ -51,7 +51,7 @@ - @result.Source.Kind.GetDisplayName() + @result.Source.Kind.DisplayName @@ -81,7 +81,7 @@ - @finding.Category.GetDisplayName() + @finding.Category.DisplayName diff --git a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor index f69288f6d..12d929484 100644 --- a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor +++ b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor @@ -23,11 +23,11 @@ @foreach (LLMProviders provider in Enum.GetValues(typeof(LLMProviders))) { - + } - + @T("Create account") @@ -45,7 +45,7 @@ } - @if (this.DataLLMProvider.IsHostnameNeeded()) + @if (this.DataLLMProvider.IsHostnameNeeded) { } - @if (this.DataLLMProvider.IsHostNeeded()) + @if (this.DataLLMProvider.IsHostNeeded) { @foreach (Host host in Enum.GetValues(typeof(Host))) { - @if (host.IsChatSupported()) + @if (host.IsChatSupported) { - @host.Name() + @host.Name } } } - @if (this.DataLLMProvider.IsHFInstanceProviderNeeded()) + @if (this.DataLLMProvider.IsHFInstanceProviderNeeded) { @foreach (HFInferenceProvider inferenceProvider in Enum.GetValues(typeof(HFInferenceProvider))) { - @if (inferenceProvider.SupportsChat()) + @if (inferenceProvider.SupportsChat) { - @inferenceProvider.ToName() + @inferenceProvider.Name } } @@ -97,7 +97,7 @@ { - @if (this.DataLLMProvider.IsLLMModelProvidedManually()) + @if (this.DataLLMProvider.IsLLMModelProvidedManually) { @T("Show available models") diff --git a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs index 9849c9f3b..866226fc6 100644 --- a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs @@ -207,7 +207,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName, GetUsedInstanceNames = () => this.UsedInstanceNames, GetHost = () => this.DataHost, - IsModelProvidedManually = () => this.DataLLMProvider.IsLLMModelProvidedManually(), + IsModelProvidedManually = () => this.DataLLMProvider.IsLLMModelProvidedManually, GetCustomTokenizerValidationIssue = () => this.dataCustomTokenizerValidationIssue, IsModelSelectionHidden = () => this.IsLLMModelSelectionHidden, }; @@ -241,7 +241,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId if (this.IsLLMModelSelectionHidden) return Model.SYSTEM_MODEL; - if (this.DataLLMProvider.IsLLMModelProvidedManually()) + if (this.DataLLMProvider.IsLLMModelProvidedManually) return new Model(this.dataManuallyModel, null); return this.DataModel; @@ -273,7 +273,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId this.dataFilePath = this.DataTokenizerPath; // When using Fireworks, we must copy the model name: - if (this.DataLLMProvider.IsLLMModelProvidedManually()) + if (this.DataLLMProvider.IsLLMModelProvidedManually) this.dataManuallyModel = this.DataModel.Id; // When editing, we need to load the data: @@ -334,7 +334,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId // 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 SecretId => this.IsEnterpriseConfiguration ? $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{this.DataLLMProvider.SecretId}" : this.DataLLMProvider.SecretId; public string SecretName => this.DataInstanceName; @@ -421,7 +421,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId private string? ValidateManuallyModel(string manuallyModel) { - if (this.DataLLMProvider.IsLLMModelProvidedManually() && string.IsNullOrWhiteSpace(manuallyModel)) + if (this.DataLLMProvider.IsLLMModelProvidedManually && string.IsNullOrWhiteSpace(manuallyModel)) return T("Please enter a model name."); return null; diff --git a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor.cs b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor.cs index 763477df4..ce992c52c 100644 --- a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor.cs +++ b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBatchProcessing.razor.cs @@ -51,32 +51,32 @@ public partial class SettingsDialogBatchProcessing : SettingsDialogBase [ .. Enum .GetValues() - .Select(value => new ConfigurationSelectData(value.Name(), value)) + .Select(value => new ConfigurationSelectData(value.Name, value)) ]; private IReadOnlyList> OutputModeData => [ .. Enum .GetValues() - .Select(value => new ConfigurationSelectData(value.Name(), value)) + .Select(value => new ConfigurationSelectData(value.Name, value)) ]; private static IReadOnlyList> ResultFileFormatData => [ - .. FileExportFormatExtensions.ANSWER_FORMATS - .Select(value => new ConfigurationSelectData(value.ToName(), value)) + .. FileExportFormat.AnswerFormats + .Select(value => new ConfigurationSelectData(value.Name, value)) ]; private IReadOnlyList> CsvSeparatorData => [ .. Enum .GetValues() - .Select(value => new ConfigurationSelectData(value.Name(), value)) + .Select(value => new ConfigurationSelectData(value.Name, value)) ]; private string? ValidateCustomCsvSeparator(string separator) { - if (!BatchProcessingCsvSeparatorExtensions.IsValidCustomSeparator(separator)) + if (!BatchProcessingCsvSeparator.IsValidCustomSeparator(separator)) return T("Please enter exactly one punctuation or symbol character. Letters, numbers, spaces, quotation marks, and line breaks cannot be used as CSV separators."); return null; diff --git a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogSlideBuilder.razor b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogSlideBuilder.razor index d80fdb193..c23c7ab63 100644 --- a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogSlideBuilder.razor +++ b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogSlideBuilder.razor @@ -59,7 +59,7 @@ { - + } @@ -83,7 +83,7 @@ { @foreach (var templateSlide in loadedTemplate.Slides) { - + } } diff --git a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogSlideBuilder.razor.cs b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogSlideBuilder.razor.cs index 05869ee93..47688f32a 100644 --- a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogSlideBuilder.razor.cs +++ b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogSlideBuilder.razor.cs @@ -112,7 +112,7 @@ public partial class SettingsDialogSlideBuilder : SettingsDialogBase /// private static List> UseOptionsOf(TemplateSlide slide) => Enum.GetValues() .Where(use => use is not TemplateSlideUse.EDIT || slide.IsEditable) - .Select(use => new ConfigurationSelectData(use.Name(), use)) + .Select(use => new ConfigurationSelectData(use.Name, use)) .ToList(); /// diff --git a/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsExportDialog.razor.cs b/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsExportDialog.razor.cs index 9aa2ffc4b..4cda59dad 100644 --- a/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsExportDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsExportDialog.razor.cs @@ -147,7 +147,7 @@ public partial class ToolSettingsExportDialog : SettingsDialogBase private string GetMinimumProviderConfidenceName() { var confidence = this.item is null ? ConfidenceLevel.NONE : this.ToolRegistry.GetMinimumProviderConfidence(this.item.Id); - return confidence is ConfidenceLevel.NONE ? T("No minimum confidence level chosen") : confidence.GetName(); + return confidence is ConfidenceLevel.NONE ? T("No minimum confidence level chosen") : confidence.Name; } private async Task Export() diff --git a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor index c2c827e05..e27041025 100644 --- a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor +++ b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor @@ -17,15 +17,15 @@ @foreach (LLMProviders provider in Enum.GetValues(typeof(LLMProviders))) { - if (provider.ProvideTranscriptionAPI() || provider is LLMProviders.NONE) + if (provider.ProvideTranscriptionAPI || provider is LLMProviders.NONE) { - + } } - + @T("Create account") @@ -43,7 +43,7 @@ } - @if (this.DataLLMProvider.IsHostnameNeeded()) + @if (this.DataLLMProvider.IsHostnameNeeded) { } - @if (this.DataLLMProvider.IsHostNeeded()) + @if (this.DataLLMProvider.IsHostNeeded) { @foreach (Host host in Enum.GetValues(typeof(Host))) { - if (host.IsTranscriptionSupported()) + if (host.IsTranscriptionSupported) { - @host.Name() + @host.Name } } } - @if (this.DataLLMProvider.IsHFInstanceProviderNeeded()) + @if (this.DataLLMProvider.IsHFInstanceProviderNeeded) { @foreach (HFInferenceProvider inferenceProvider in Enum.GetValues(typeof(HFInferenceProvider))) { - @if (inferenceProvider.SupportsTranscription()) + @if (inferenceProvider.SupportsTranscription) { - @inferenceProvider.ToName() + @inferenceProvider.Name } } diff --git a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs index fc0989954..e83f33204 100644 --- a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs @@ -240,7 +240,7 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId // 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 SecretId => this.IsEnterpriseConfiguration ? $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{this.DataLLMProvider.SecretId}" : this.DataLLMProvider.SecretId; public string SecretName => this.DataName; diff --git a/app/MindWork AI Studio/Layout/MainLayout.razor.cs b/app/MindWork AI Studio/Layout/MainLayout.razor.cs index 45412ae93..c621bf806 100644 --- a/app/MindWork AI Studio/Layout/MainLayout.razor.cs +++ b/app/MindWork AI Studio/Layout/MainLayout.razor.cs @@ -487,8 +487,8 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan private IEnumerable GetNavItems() { var palette = this.ColorTheme.GetCurrentPalette(this.SettingsManager); - var activityIndicatorLightColor = this.ColorTheme.GetActivityIndicatorLightColor(); - var activityIndicatorDarkColor = this.ColorTheme.GetActivityIndicatorDarkColor(); + var activityIndicatorLightColor = this.ColorTheme.ActivityIndicatorLightColor; + var activityIndicatorDarkColor = this.ColorTheme.ActivityIndicatorDarkColor; var defaultLightColor = palette.DarkLighten; var defaultDarkColor = palette.GrayLight; var mediaSnapshots = this.MediaTranscriptionService.GetSnapshots(); diff --git a/app/MindWork AI Studio/Pages/Assistants.razor b/app/MindWork AI Studio/Pages/Assistants.razor index bb8209109..0ff7659d9 100644 --- a/app/MindWork AI Studio/Pages/Assistants.razor +++ b/app/MindWork AI Studio/Pages/Assistants.razor @@ -65,7 +65,7 @@ - + diff --git a/app/MindWork AI Studio/Pages/Embeddings.razor.cs b/app/MindWork AI Studio/Pages/Embeddings.razor.cs index 0c3b9fd71..e0c798191 100644 --- a/app/MindWork AI Studio/Pages/Embeddings.razor.cs +++ b/app/MindWork AI Studio/Pages/Embeddings.razor.cs @@ -321,15 +321,15 @@ public partial class Embeddings : MSGComponentBase // if (failure.FailureReason is not ProviderRequestFailureReason.NONE) { - var isFixedInSettings = failure.FailureReason.IsFixedInProviderSettings(); - return new FailureCause(isFixedInSettings ? 0 : 1, failure.FailureReason.GetName(), isFixedInSettings ? Icons.Material.Filled.Key : Icons.Material.Filled.CloudOff, Color.Error, false, isFixedInSettings, true); + var isFixedInSettings = failure.FailureReason.IsFixedInProviderSettings; + return new FailureCause(isFixedInSettings ? 0 : 1, failure.FailureReason.Name, isFixedInSettings ? Icons.Material.Filled.Key : Icons.Material.Filled.CloudOff, Color.Error, false, isFixedInSettings, true); } // // Codes without a name of their own carry everything they know in the message of the // single file, which is why those groups show that message per file: // - var causeName = failure.ExtractionCode.GetIndexingCauseName(); + var causeName = failure.ExtractionCode.IndexingCauseName; var hasCauseName = !string.IsNullOrWhiteSpace(causeName); var title = hasCauseName ? causeName : T("Other cause"); diff --git a/app/MindWork AI Studio/Pages/Home.razor.cs b/app/MindWork AI Studio/Pages/Home.razor.cs index 1a8fe5b2a..b5231229f 100644 --- a/app/MindWork AI Studio/Pages/Home.razor.cs +++ b/app/MindWork AI Studio/Pages/Home.razor.cs @@ -66,7 +66,7 @@ public partial class Home : MSGComponentBase return; this.SettingsManager.StartupStartPageRedirectHandled = true; - var startPageRoute = this.SettingsManager.ConfigurationData.App.StartPage.ToRoute(); + var startPageRoute = this.SettingsManager.ConfigurationData.App.StartPage.Route; if (string.IsNullOrWhiteSpace(startPageRoute)) return; diff --git a/app/MindWork AI Studio/Pages/Information.razor.cs b/app/MindWork AI Studio/Pages/Information.razor.cs index 1b457a33c..44fa5e21e 100644 --- a/app/MindWork AI Studio/Pages/Information.razor.cs +++ b/app/MindWork AI Studio/Pages/Information.razor.cs @@ -49,7 +49,7 @@ public partial class Information : MSGComponentBase private string osUserName = string.Empty; private UpdatePolicyMode updatePolicyMode; - private static string VersionApp => $"MindWork AI Studio: v{META_DATA.Version} (commit {META_DATA.AppCommitHash}, build {META_DATA.BuildNum}, {META_DATA_ARCH.Architecture.ToRID().ToUserFriendlyName()})"; + private static string VersionApp => $"MindWork AI Studio: v{META_DATA.Version} (commit {META_DATA.AppCommitHash}, build {META_DATA.BuildNum}, {META_DATA_ARCH.Architecture.ToRID().UserFriendlyName})"; private static string MudBlazorVersion => $"MudBlazor: v{META_DATA.MudBlazorVersion}"; @@ -203,26 +203,20 @@ public partial class Information : MSGComponentBase /// Determines whether the enterprise configuration has details that can be shown/hidden. /// Returns true if there are details available, false otherwise. /// - private bool HasEnterpriseConfigurationDetails + private bool HasEnterpriseConfigurationDetails => this.HasAnyActiveEnvironment switch { - get - { - return this.HasAnyActiveEnvironment switch - { - // Case 1: No enterprise config and no plugin - no details available - false when this.configPlugins.Count == 0 => false, + // Case 1: No enterprise config and no plugin - no details available + false when this.configPlugins.Count == 0 => false, - // Case 2: Enterprise config with plugin but no central management - has details - false => true, + // Case 2: Enterprise config with plugin but no central management - has details + false => true, - // Case 3: Enterprise config active but no plugin - has details - true when this.configPlugins.Count == 0 => true, + // Case 3: Enterprise config active but no plugin - has details + true when this.configPlugins.Count == 0 => true, - // Case 4: Enterprise config active with plugin - has details - true => true - }; - } - } + // Case 4: Enterprise config active with plugin - has details + true => true + }; #region Overrides of ComponentBase @@ -321,19 +315,13 @@ public partial class Information : MSGComponentBase await this.InvokeAsync(this.StateHasChanged); } - private string PandocButtonText + private string PandocButtonText => this.pandocInstallation switch { - get - { - return this.pandocInstallation switch - { - { IsAvailable: true, CheckWasSuccessful: true } => this.T("Check Pandoc Installation"), - { IsAvailable: false, CheckWasSuccessful: true } => this.T("Update Pandoc"), - - _ => this.T("Install Pandoc") - }; - } - } + { IsAvailable: true, CheckWasSuccessful: true } => this.T("Check Pandoc Installation"), + { IsAvailable: false, CheckWasSuccessful: true } => this.T("Update Pandoc"), + + _ => this.T("Install Pandoc") + }; private async Task ShowPandocDialog() { diff --git a/app/MindWork AI Studio/Pages/Plugins.razor.cs b/app/MindWork AI Studio/Pages/Plugins.razor.cs index ab397bcdf..8ee276018 100644 --- a/app/MindWork AI Studio/Pages/Plugins.razor.cs +++ b/app/MindWork AI Studio/Pages/Plugins.razor.cs @@ -123,7 +123,7 @@ public partial class Plugins : MSGComponentBase { var blockedAudit = securityState.Audit; if (blockedAudit is not null) - await this.DialogService.ShowMessageBoxAsync(this.T("Assistant Audit"), $"{blockedAudit.Level.GetName()}: {blockedAudit.Summary}", this.T("Close")); + await this.DialogService.ShowMessageBoxAsync(this.T("Assistant Audit"), $"{blockedAudit.Level.Name}: {blockedAudit.Summary}", this.T("Close")); return; } @@ -168,8 +168,8 @@ public partial class Plugins : MSGComponentBase string.Format( this.T("The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level '{2}'. Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?"), pluginName, - actualLevel.GetName(), - this.AssistantPluginAuditSettings.MinimumLevel.GetName()) + actualLevel.Name, + this.AssistantPluginAuditSettings.MinimumLevel.Name) }, }; diff --git a/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs b/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs index 2edb690d6..635dfafef 100644 --- a/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs +++ b/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs @@ -13,7 +13,7 @@ public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_C #region Implementation of IProvider /// - public override string Id => LLMProviders.ALIBABA_CLOUD.ToSecretId(); + public override string Id => LLMProviders.ALIBABA_CLOUD.SecretId; /// public override string InstanceName { get; set; } = "AlibabaCloud"; diff --git a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs index dfa60864a..52dacb200 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs @@ -17,7 +17,7 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, n #region Implementation of IProvider /// - public override string Id => LLMProviders.ANTHROPIC.ToSecretId(); + public override string Id => LLMProviders.ANTHROPIC.SecretId; /// public override string InstanceName { get; set; } = "Anthropic"; diff --git a/app/MindWork AI Studio/Provider/BaseProvider.cs b/app/MindWork AI Studio/Provider/BaseProvider.cs index ceec463f6..5e18af007 100644 --- a/app/MindWork AI Studio/Provider/BaseProvider.cs +++ b/app/MindWork AI Studio/Provider/BaseProvider.cs @@ -1573,7 +1573,7 @@ public abstract class BaseProvider : IProvider, ISecretId // form.Add(new StringContent("json"), "response_format"); - using var request = new HttpRequestMessage(HttpMethod.Post, host.TranscriptionURL()); + using var request = new HttpRequestMessage(HttpMethod.Post, host.TranscriptionURL); request.Content = form; // Handle the authorization header based on the provider: @@ -1664,7 +1664,7 @@ public abstract class BaseProvider : IProvider, ISecretId // Prepare the HTTP embedding request: var payload = new EmbeddingRequest(modelName, texts); var embeddingRequest = JsonSerializer.Serialize(payload, JSON_SERIALIZER_OPTIONS); - using var request = new HttpRequestMessage(HttpMethod.Post, host.EmbeddingURL()); + using var request = new HttpRequestMessage(HttpMethod.Post, host.EmbeddingURL); // Handle the authorization header based on the provider: switch (this.Provider) diff --git a/app/MindWork AI Studio/Provider/ConfidenceLevelExtensions.cs b/app/MindWork AI Studio/Provider/ConfidenceLevelExtensions.cs index 22d12227a..1f85e3f5d 100644 --- a/app/MindWork AI Studio/Provider/ConfidenceLevelExtensions.cs +++ b/app/MindWork AI Studio/Provider/ConfidenceLevelExtensions.cs @@ -9,7 +9,7 @@ public static class ConfidenceLevelExtensions extension(ConfidenceLevel level) { - public string GetName() => level switch + public string Name => level switch { ConfidenceLevel.NONE => TB("No provider selected"), diff --git a/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs b/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs index ab70d172b..6fb7fe0c1 100644 --- a/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs +++ b/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs @@ -13,7 +13,7 @@ public sealed class ProviderDeepSeek() : BaseProvider(LLMProviders.DEEP_SEEK, ne #region Implementation of IProvider /// - public override string Id => LLMProviders.DEEP_SEEK.ToSecretId(); + public override string Id => LLMProviders.DEEP_SEEK.SecretId; /// public override string InstanceName { get; set; } = "DeepSeek"; diff --git a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs index 0c4400687..c2ed05993 100644 --- a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs +++ b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs @@ -13,7 +13,7 @@ public class ProviderFireworks() : BaseProvider(LLMProviders.FIREWORKS, new Uri( #region Implementation of IProvider /// - public override string Id => LLMProviders.FIREWORKS.ToSecretId(); + public override string Id => LLMProviders.FIREWORKS.SecretId; /// public override string InstanceName { get; set; } = "Fireworks.ai"; diff --git a/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs b/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs index 881db06d6..adcd9f138 100644 --- a/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs +++ b/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs @@ -28,7 +28,7 @@ public sealed class ProviderGWDG() : BaseProvider(LLMProviders.GWDG, new Uri("ht #region Implementation of IProvider /// - public override string Id => LLMProviders.GWDG.ToSecretId(); + public override string Id => LLMProviders.GWDG.SecretId; /// public override string InstanceName { get; set; } = "GWDG SAIA"; diff --git a/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs b/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs index 0cdc533e2..9475dd815 100644 --- a/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs +++ b/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs @@ -15,7 +15,7 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, new Uri("https #region Implementation of IProvider /// - public override string Id => LLMProviders.GOOGLE.ToSecretId(); + public override string Id => LLMProviders.GOOGLE.SecretId; /// public override string InstanceName { get; set; } = "Google Gemini"; diff --git a/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs b/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs index 6a5630744..d31ebafc2 100644 --- a/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs +++ b/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs @@ -14,7 +14,7 @@ public class ProviderGroq() : BaseProvider(LLMProviders.GROQ, new Uri("https://a #region Implementation of IProvider /// - public override string Id => LLMProviders.GROQ.ToSecretId(); + public override string Id => LLMProviders.GROQ.SecretId; /// public override string InstanceName { get; set; } = "Groq"; diff --git a/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs b/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs index 5b88e880c..1be75bba4 100644 --- a/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs +++ b/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs @@ -15,7 +15,7 @@ public sealed class ProviderHelmholtz() : BaseProvider(LLMProviders.HELMHOLTZ, n #region Implementation of IProvider /// - public override string Id => LLMProviders.HELMHOLTZ.ToSecretId(); + public override string Id => LLMProviders.HELMHOLTZ.SecretId; /// public override string InstanceName { get; set; } = "Helmholtz Blablador"; diff --git a/app/MindWork AI Studio/Provider/Hetzner/ProviderHetzner.cs b/app/MindWork AI Studio/Provider/Hetzner/ProviderHetzner.cs index 59080adac..9ae99f21b 100644 --- a/app/MindWork AI Studio/Provider/Hetzner/ProviderHetzner.cs +++ b/app/MindWork AI Studio/Provider/Hetzner/ProviderHetzner.cs @@ -13,7 +13,7 @@ public sealed class ProviderHetzner() : BaseProvider(LLMProviders.HETZNER, new U #region Implementation of IProvider /// - public override string Id => LLMProviders.HETZNER.ToSecretId(); + public override string Id => LLMProviders.HETZNER.SecretId; /// public override string InstanceName { get; set; } = "Hetzner (Experimental)"; diff --git a/app/MindWork AI Studio/Provider/HuggingFace/HFInferenceProviderExtensions.cs b/app/MindWork AI Studio/Provider/HuggingFace/HFInferenceProviderExtensions.cs index 0ffc33c25..d23555761 100644 --- a/app/MindWork AI Studio/Provider/HuggingFace/HFInferenceProviderExtensions.cs +++ b/app/MindWork AI Studio/Provider/HuggingFace/HFInferenceProviderExtensions.cs @@ -12,8 +12,8 @@ public static class HFInferenceProviderExtensions /// /// The slug Hugging Face uses for this inference provider. /// - /// The slug, or an empty string for the routing strategies, which name no provider. - public string EndpointsId() => provider switch + /// The slug, or an empty string for the routing strategies, which name no provider. + public string EndpointsId => provider switch { HFInferenceProvider.BASETEN => "baseten", HFInferenceProvider.CEREBRAS => "cerebras", @@ -41,22 +41,22 @@ public static class HFInferenceProviderExtensions /// a suffix on the model name, e.g. "google/gemma-4-31B-it:novita". Without a suffix, the router /// picks the fastest provider itself. /// - /// The suffix including its colon, or an empty string when the router should choose. - public string ModelSuffix() => provider switch + /// The suffix including its colon, or an empty string when the router should choose. + public string ModelSuffix => provider switch { HFInferenceProvider.NONE or HFInferenceProvider.AUTOMATIC => string.Empty, HFInferenceProvider.CHEAPEST => ":cheapest", HFInferenceProvider.PREFERRED => ":preferred", - _ => $":{provider.EndpointsId()}", + _ => $":{provider.EndpointsId}", }; /// /// Whether this inference provider serves models to chat with. /// - /// True, when the provider serves chat models. - public bool SupportsChat() => provider is not HFInferenceProvider.NONE; + /// True, when the provider serves chat models. + public bool SupportsChat => provider is not HFInferenceProvider.NONE; /// /// Whether this inference provider creates embeddings for us. @@ -67,8 +67,8 @@ public static class HFInferenceProviderExtensions /// OpenAI-compatible form we send. The routing strategies are out by their nature: without a /// named provider there is no route to address. /// - /// True, when we can create embeddings through this provider. - public bool SupportsEmbeddings() => provider is HFInferenceProvider.TOGETHER_AI or HFInferenceProvider.DEEPINFRA; + /// True, when we can create embeddings through this provider. + public bool SupportsEmbeddings => provider is HFInferenceProvider.TOGETHER_AI or HFInferenceProvider.DEEPINFRA; /// /// Whether this inference provider transcribes audio for us. @@ -79,8 +79,8 @@ public static class HFInferenceProviderExtensions /// transcribe for Hugging Face, but not in a shape we could send an audio file to: fal-ai and /// Replicate both turn the request down with "Model not supported by provider". /// - /// True, when we can transcribe audio through this provider. - public bool SupportsTranscription() => provider is HFInferenceProvider.TOGETHER_AI or HFInferenceProvider.DEEPINFRA; + /// True, when we can transcribe audio through this provider. + public bool SupportsTranscription => provider is HFInferenceProvider.TOGETHER_AI or HFInferenceProvider.DEEPINFRA; /// /// The base URL of the provider's own OpenAI-compatible route. @@ -91,8 +91,8 @@ public static class HFInferenceProviderExtensions /// keeps it below an additional "openai" segment, and answers the path without it with /// "Not allowed to POST /v1/embeddings for provider deepinfra". /// - /// The base URL, or an empty string when the provider has no such route. - public string ProviderBaseURL() => provider switch + /// The base URL, or an empty string when the provider has no such route. + public string ProviderBaseURL => provider switch { HFInferenceProvider.TOGETHER_AI => "https://router.huggingface.co/together/v1/", HFInferenceProvider.DEEPINFRA => "https://router.huggingface.co/deepinfra/v1/openai/", @@ -103,14 +103,17 @@ public static class HFInferenceProviderExtensions /// /// The value to filter the Hugging Face model catalog by. /// - /// The provider slug, or "all" when no particular provider was chosen. - public string CatalogFilter() + /// The provider slug, or "all" when no particular provider was chosen. + public string CatalogFilter { - var slug = provider.EndpointsId(); - return string.IsNullOrEmpty(slug) ? "all" : slug; + get + { + var slug = provider.EndpointsId; + return string.IsNullOrEmpty(slug) ? "all" : slug; + } } - public string ToName() => provider switch + public string Name => provider switch { HFInferenceProvider.AUTOMATIC => TB("Automatic: the fastest provider"), HFInferenceProvider.CHEAPEST => TB("Automatic: the cheapest provider"), diff --git a/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs b/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs index 6df9f7000..3e2f49b38 100644 --- a/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs +++ b/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs @@ -64,7 +64,7 @@ public sealed class ProviderHuggingFace : BaseProvider if (endpointKind is HFEndpointKind.CHAT) return ROUTER_BASE_URL; - var providerBaseURL = hfProvider.ProviderBaseURL(); + var providerBaseURL = hfProvider.ProviderBaseURL; return string.IsNullOrEmpty(providerBaseURL) ? ROUTER_BASE_URL : providerBaseURL; } @@ -83,7 +83,7 @@ public sealed class ProviderHuggingFace : BaseProvider if (string.IsNullOrWhiteSpace(modelId) || modelId.Contains(':')) return modelId; - return $"{modelId}{this.hfProvider.ModelSuffix()}"; + return $"{modelId}{this.hfProvider.ModelSuffix}"; } /// @@ -141,7 +141,7 @@ public sealed class ProviderHuggingFace : BaseProvider if (this.hfProvider is HFInferenceProvider.NONE or HFInferenceProvider.AUTOMATIC or HFInferenceProvider.CHEAPEST or HFInferenceProvider.PREFERRED) return TB("No Hugging Face inference provider offers the selected model. Please check the model name and whether it is still available on Hugging Face."); - return string.Format(TB("The Hugging Face inference provider '{0}' does not offer the selected model. Please select another inference provider, or let Hugging Face choose one for you."), this.hfProvider.ToName()); + return string.Format(TB("The Hugging Face inference provider '{0}' does not offer the selected model. Please select another inference provider, or let Hugging Face choose one for you."), this.hfProvider.Name); } #endregion @@ -149,7 +149,7 @@ public sealed class ProviderHuggingFace : BaseProvider #region Implementation of IProvider /// - public override string Id => LLMProviders.HUGGINGFACE.ToSecretId(); + public override string Id => LLMProviders.HUGGINGFACE.SecretId; /// public override string InstanceName { get; set; } = "HuggingFace"; @@ -247,7 +247,7 @@ public sealed class ProviderHuggingFace : BaseProvider /// One listing per model, which says nothing for the models nobody stated a window for. private IEnumerable ListingsOf(ModelsResponse response) { - var providerSlug = this.hfProvider.EndpointsId(); + var providerSlug = this.hfProvider.EndpointsId; return response.Data.Select(hfModel => ModelListing.For(hfModel.Id, hfModel.ContextWindowTokens(providerSlug))); } @@ -265,7 +265,7 @@ public sealed class ProviderHuggingFace : BaseProvider private IEnumerable SelectChatModels(ModelsResponse response) { var chatModels = response.Data.Where(hfModel => new Model(hfModel.Id, null).IsChatModel(this.Provider)); - var providerSlug = this.hfProvider.EndpointsId(); + var providerSlug = this.hfProvider.EndpointsId; if (string.IsNullOrEmpty(providerSlug)) return ToModels(chatModels); @@ -293,7 +293,7 @@ public sealed class ProviderHuggingFace : BaseProvider /// public override Task GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) { - if (!this.hfProvider.SupportsEmbeddings()) + if (!this.hfProvider.SupportsEmbeddings) return Task.FromResult(ModelLoadResult.FromModels([])); return this.LoadHubModels(SecretStoreType.EMBEDDING_PROVIDER, "feature-extraction", apiKeyProvisional, token); @@ -309,14 +309,14 @@ public sealed class ProviderHuggingFace : BaseProvider /// The models of that provider for that task. private Task LoadHubModels(SecretStoreType storeType, string pipelineTag, string? apiKeyProvisional, CancellationToken token) { - var requestURL = $"{HUB_MODELS_URL}{this.hfProvider.EndpointsId()}&pipeline_tag={pipelineTag}"; + var requestURL = $"{HUB_MODELS_URL}{this.hfProvider.EndpointsId}&pipeline_tag={pipelineTag}"; return this.LoadModelsResponse>(storeType, requestURL, hubModels => hubModels.Select(hubModel => new Model(hubModel.Id, null)), apiKeyProvisional, token: token); } /// public override Task GetTranscriptionModels(string? apiKeyProvisional = null, CancellationToken token = default) { - if (!this.hfProvider.SupportsTranscription()) + if (!this.hfProvider.SupportsTranscription) return Task.FromResult(ModelLoadResult.FromModels([])); return this.LoadHubModels(SecretStoreType.TRANSCRIPTION_PROVIDER, "automatic-speech-recognition", apiKeyProvisional, token); diff --git a/app/MindWork AI Studio/Provider/IONOS/ProviderIONOS.cs b/app/MindWork AI Studio/Provider/IONOS/ProviderIONOS.cs index a15fe3766..66beadb18 100644 --- a/app/MindWork AI Studio/Provider/IONOS/ProviderIONOS.cs +++ b/app/MindWork AI Studio/Provider/IONOS/ProviderIONOS.cs @@ -20,7 +20,7 @@ public sealed class ProviderIONOS() : BaseProvider(LLMProviders.IONOS, new Uri(" #region Implementation of IProvider /// - public override string Id => LLMProviders.IONOS.ToSecretId(); + public override string Id => LLMProviders.IONOS.SecretId; /// public override string InstanceName { get; set; } = "IONOS"; diff --git a/app/MindWork AI Studio/Provider/LLMProvidersExtensions.cs b/app/MindWork AI Studio/Provider/LLMProvidersExtensions.cs index b415e0aaa..40fa96ecb 100644 --- a/app/MindWork AI Studio/Provider/LLMProvidersExtensions.cs +++ b/app/MindWork AI Studio/Provider/LLMProvidersExtensions.cs @@ -40,8 +40,8 @@ public static class LLMProvidersExtensions /// This value is UI text and may be localized. Do not use it for persisted IDs, secret namespaces, /// or other stable identifiers. /// - /// The human-readable name of the provider. - public string ToName() => provider.ToName(translate: true); + /// The human-readable name of the provider. + public string Name => provider.ToName(translate: true); /// /// Returns the human-readable name of the provider. @@ -85,8 +85,8 @@ public static class LLMProvidersExtensions /// These values are used for OS keyring namespaces. They must never be localized or changed without /// an explicit migration for existing API keys. /// - /// The stable secret namespace for the provider. - public string ToSecretId() => provider switch + /// The stable secret namespace for the provider. + public string SecretId => provider switch { LLMProviders.NONE => "No provider selected", @@ -195,8 +195,8 @@ public static class LLMProvidersExtensions /// /// Determines if the specified provider supports embeddings. /// - /// True if the provider supports embeddings; otherwise, false. - public bool ProvideEmbeddingAPI() => provider switch + /// True if the provider supports embeddings; otherwise, false. + public bool ProvideEmbeddingAPI => provider switch { // // Providers that support embeddings: @@ -239,7 +239,7 @@ public static class LLMProvidersExtensions _ => false, }; - public bool ProvideTranscriptionAPI() => provider switch + public bool ProvideTranscriptionAPI => provider switch { // // Providers that support transcription: @@ -294,8 +294,8 @@ public static class LLMProvidersExtensions /// larger images through another provider. What we actually send is asked through /// IImageSourceExtensions.MaxImageSizeBytesFor, which also applies our own limit. /// - /// The size limit of one image file, or null when the provider states none we know of. - public long? GetMaxImageSizeBytes() => provider switch + /// The size limit of one image file, or null when the provider states none we know of. + public long? MaxImageSizeBytes => provider switch { // // Anthropic accepts at most 5 MiB (5,242,880 bytes) of base64 per image. Base64 needs four @@ -360,7 +360,7 @@ public static class LLMProvidersExtensions } } - public string GetCreationURL() => provider switch + public string CreationURL => provider switch { LLMProviders.OPEN_AI => "https://platform.openai.com/signup", LLMProviders.MISTRAL => "https://console.mistral.ai/", @@ -385,7 +385,7 @@ public static class LLMProvidersExtensions _ => string.Empty, }; - public string GetDashboardURL() => provider switch + public string DashboardURL => provider switch { LLMProviders.OPEN_AI => "https://platform.openai.com/usage", LLMProviders.MISTRAL => "https://console.mistral.ai/usage/", @@ -408,7 +408,7 @@ public static class LLMProvidersExtensions _ => string.Empty, }; - public bool HasDashboard() => provider switch + public bool HasDashboard => provider switch { LLMProviders.OPEN_AI => true, LLMProviders.MISTRAL => true, @@ -434,11 +434,11 @@ public static class LLMProvidersExtensions public string GetModelsOverviewURL(HFInferenceProvider inferenceProvider) => provider switch { LLMProviders.FIREWORKS => "https://fireworks.ai/models?show=Serverless", - LLMProviders.HUGGINGFACE => $"https://huggingface.co/models?inference_provider={inferenceProvider.CatalogFilter()}", + LLMProviders.HUGGINGFACE => $"https://huggingface.co/models?inference_provider={inferenceProvider.CatalogFilter}", _ => string.Empty, }; - public bool IsLLMModelProvidedManually() => provider switch + public bool IsLLMModelProvidedManually => provider switch { LLMProviders.FIREWORKS => true, _ => false, @@ -467,13 +467,13 @@ public static class LLMProvidersExtensions _ => false, }; - public bool IsHostNeeded() => provider switch + public bool IsHostNeeded => provider switch { LLMProviders.SELF_HOSTED => true, _ => false, }; - public bool IsHostnameNeeded() => provider switch + public bool IsHostnameNeeded => provider switch { LLMProviders.SELF_HOSTED => true, LLMProviders.LITE_LLM => true, @@ -490,8 +490,8 @@ public static class LLMProvidersExtensions /// today: whether a dialog asks for a hostname is a question of the user interface, and it must /// never silently decide what a server learns about the user. /// - /// True when the provider runs on a self-hosted server; otherwise, false. - public bool RunsOnSelfHostedServer() => provider switch + /// True when the provider runs on a self-hosted server; otherwise, false. + public bool RunsOnSelfHostedServer => provider switch { LLMProviders.SELF_HOSTED => true, LLMProviders.LITE_LLM => true, @@ -529,7 +529,7 @@ public static class LLMProvidersExtensions _ => false, }; - public bool ShowRegisterButton() => provider switch + public bool ShowRegisterButton => provider switch { LLMProviders.OPEN_AI => true, LLMProviders.MISTRAL => true, @@ -556,7 +556,7 @@ public static class LLMProvidersExtensions public bool CanLoadModels(Host host, string? apiKey) { if (provider is LLMProviders.SELF_HOSTED) - return host.IsModelListSupported(); + return host.IsModelListSupported; if(provider is LLMProviders.NONE) return false; @@ -567,7 +567,7 @@ public static class LLMProvidersExtensions return true; } - public bool IsHFInstanceProviderNeeded() => provider switch + public bool IsHFInstanceProviderNeeded => provider switch { LLMProviders.HUGGINGFACE => true, _ => false, diff --git a/app/MindWork AI Studio/Provider/LiteLLM/ProviderLiteLLM.cs b/app/MindWork AI Studio/Provider/LiteLLM/ProviderLiteLLM.cs index dbcafa4cf..b3f36aebe 100644 --- a/app/MindWork AI Studio/Provider/LiteLLM/ProviderLiteLLM.cs +++ b/app/MindWork AI Studio/Provider/LiteLLM/ProviderLiteLLM.cs @@ -13,7 +13,7 @@ public sealed class ProviderLiteLLM(string hostname) : BaseProvider(LLMProviders #region Implementation of IProvider /// - public override string Id => LLMProviders.LITE_LLM.ToSecretId(); + public override string Id => LLMProviders.LITE_LLM.SecretId; /// public override string InstanceName { get; set; } = "LiteLLM"; diff --git a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs index f397922b3..e5d4678b1 100644 --- a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs +++ b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs @@ -14,7 +14,7 @@ public sealed class ProviderMistral() : BaseProvider(LLMProviders.MISTRAL, new U #region Implementation of IProvider /// - public override string Id => LLMProviders.MISTRAL.ToSecretId(); + public override string Id => LLMProviders.MISTRAL.SecretId; /// public override string InstanceName { get; set; } = "Mistral"; diff --git a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs index 13e8eb4f1..273b5280e 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs @@ -25,7 +25,7 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur #region Implementation of IProvider /// - public override string Id => LLMProviders.OPEN_AI.ToSecretId(); + public override string Id => LLMProviders.OPEN_AI.SecretId; /// public override string InstanceName { get; set; } = "OpenAI"; @@ -71,7 +71,7 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur // OpenAI changed the role of the system prompt from one generation to the next, and the // early reasoning models take no system prompt at all. Which role a model takes is stated // by the OpenAI families in Models/OpenAI: - var systemPromptRole = modelProfile.SystemPromptRole.ToOpenAIRole(); + var systemPromptRole = modelProfile.SystemPromptRole.OpenAIRole; // Check if we are using the Responses API or the Chat Completion API: var usingResponsesAPI = modelProfile.Has(Capability.RESPONSES_API); diff --git a/app/MindWork AI Studio/Provider/OpenAI/SystemPromptRoleExtensions.cs b/app/MindWork AI Studio/Provider/OpenAI/SystemPromptRoleExtensions.cs index 2ee0c4a95..a3d6b2010 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/SystemPromptRoleExtensions.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/SystemPromptRoleExtensions.cs @@ -15,8 +15,8 @@ public static class SystemPromptRoleExtensions /// model the rules do not know is almost always one released after they were written, and the /// older generations which still want "system" say so in their families. /// - /// The role, as OpenAI names it. - public string ToOpenAIRole() => role switch + /// The role, as OpenAI names it. + public string OpenAIRole => role switch { SystemPromptRole.SYSTEM => "system", SystemPromptRole.DEVELOPER => "developer", diff --git a/app/MindWork AI Studio/Provider/OpenRouter/ProviderOpenRouter.cs b/app/MindWork AI Studio/Provider/OpenRouter/ProviderOpenRouter.cs index 7df8e3326..d250c9c31 100644 --- a/app/MindWork AI Studio/Provider/OpenRouter/ProviderOpenRouter.cs +++ b/app/MindWork AI Studio/Provider/OpenRouter/ProviderOpenRouter.cs @@ -15,7 +15,7 @@ public sealed class ProviderOpenRouter() : BaseProvider(LLMProviders.OPEN_ROUTER #region Implementation of IProvider /// - public override string Id => LLMProviders.OPEN_ROUTER.ToSecretId(); + public override string Id => LLMProviders.OPEN_ROUTER.SecretId; /// public override string InstanceName { get; set; } = "OpenRouter"; diff --git a/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs b/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs index 1d6156373..1dbc60e48 100644 --- a/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs +++ b/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs @@ -22,7 +22,7 @@ public sealed class ProviderPerplexity() : BaseProvider(LLMProviders.PERPLEXITY, #region Implementation of IProvider /// - public override string Id => LLMProviders.PERPLEXITY.ToSecretId(); + public override string Id => LLMProviders.PERPLEXITY.SecretId; /// public override string InstanceName { get; set; } = "Perplexity"; diff --git a/app/MindWork AI Studio/Provider/ProviderRequestFailureReasonExtensions.cs b/app/MindWork AI Studio/Provider/ProviderRequestFailureReasonExtensions.cs index 1346406c9..9bd30fffa 100644 --- a/app/MindWork AI Studio/Provider/ProviderRequestFailureReasonExtensions.cs +++ b/app/MindWork AI Studio/Provider/ProviderRequestFailureReasonExtensions.cs @@ -15,7 +15,7 @@ public static class ProviderRequestFailureReasonExtensions /// Meant as a label beside the full message, so a list of failures can be scanned instead of /// read: twenty entries which all say API key are one problem, not twenty. /// - public string GetName() => failureReason switch + public string Name => failureReason switch { ProviderRequestFailureReason.INSUFFICIENT_QUOTA => TB("No credits left"), ProviderRequestFailureReason.TOO_MANY_REQUESTS => TB("Too many requests"), @@ -39,7 +39,7 @@ public static class ProviderRequestFailureReasonExtensions /// Only for the failures a setting actually fixes. Pointing at the settings for a provider /// which is merely overloaded would send the user looking for a mistake they never made. /// - public bool IsFixedInProviderSettings() => failureReason is + public bool IsFixedInProviderSettings => failureReason is ProviderRequestFailureReason.INVALID_OR_MISSING_API_KEY or ProviderRequestFailureReason.AUTHENTICATION_OR_PERMISSION_ERROR or ProviderRequestFailureReason.MODEL_NOT_FOUND or diff --git a/app/MindWork AI Studio/Provider/Requesty/ProviderRequesty.cs b/app/MindWork AI Studio/Provider/Requesty/ProviderRequesty.cs index 49158ae4c..3e6b1de2f 100644 --- a/app/MindWork AI Studio/Provider/Requesty/ProviderRequesty.cs +++ b/app/MindWork AI Studio/Provider/Requesty/ProviderRequesty.cs @@ -15,7 +15,7 @@ public sealed class ProviderRequesty() : BaseProvider(LLMProviders.REQUESTY, new #region Implementation of IProvider /// - public override string Id => LLMProviders.REQUESTY.ToSecretId(); + public override string Id => LLMProviders.REQUESTY.SecretId; /// public override string InstanceName { get; set; } = "Requesty"; diff --git a/app/MindWork AI Studio/Provider/SelfHosted/HostExtensions.cs b/app/MindWork AI Studio/Provider/SelfHosted/HostExtensions.cs index 037246edb..5093deecd 100644 --- a/app/MindWork AI Studio/Provider/SelfHosted/HostExtensions.cs +++ b/app/MindWork AI Studio/Provider/SelfHosted/HostExtensions.cs @@ -5,7 +5,7 @@ public static class HostExtensions /// The engine. extension(Host host) { - public string Name() => host switch + public string Name => host switch { Host.NONE => "None", @@ -19,22 +19,22 @@ public static class HostExtensions _ => "Unknown", }; - public string BaseURL() => host switch + public string BaseURL => host switch { _ => "/v1/", }; - public string ChatURL() => host switch + public string ChatURL => host switch { _ => "chat/completions", }; - public string TranscriptionURL() => host switch + public string TranscriptionURL => host switch { _ => "audio/transcriptions", }; - public string EmbeddingURL() => host switch + public string EmbeddingURL => host switch { _ => "embeddings", }; @@ -43,12 +43,12 @@ public static class HostExtensions /// The largest image file, in bytes, which the engine accepts in a chat request, where we know of one. /// /// - /// Like the limit of a cloud provider, see LLMProvidersExtensions.GetMaxImageSizeBytes, this + /// Like the limit of a cloud provider, see LLMProvidersExtensions.MaxImageSizeBytes, this /// belongs to the API of the engine, not to the model. What we actually send is asked through /// IImageSourceExtensions.MaxImageSizeBytesFor. /// - /// The size limit of one image file, or null when the engine states none we know of. - public long? GetMaxImageSizeBytes() => host switch + /// The size limit of one image file, or null when the engine states none we know of. + public long? MaxImageSizeBytes => host switch { // // llmman answers a chat request larger than 2 MiB with 413: its route /v1/chat/completions @@ -61,53 +61,62 @@ public static class HostExtensions _ => null, }; - public bool IsChatSupported() + public bool IsChatSupported { - switch (host) + get { - case Host.WHISPER_CPP: - return false; - - default: - case Host.OLLAMA: - case Host.VLLM: - case Host.LM_STUDIO: - case Host.LLAMA_CPP: - case Host.LLMMAN: - return true; + switch (host) + { + case Host.WHISPER_CPP: + return false; + + default: + case Host.OLLAMA: + case Host.VLLM: + case Host.LM_STUDIO: + case Host.LLAMA_CPP: + case Host.LLMMAN: + return true; + } } } - public bool IsEmbeddingSupported() + public bool IsEmbeddingSupported { - switch (host) + get { - case Host.LM_STUDIO: - case Host.OLLAMA: - case Host.VLLM: - case Host.LLMMAN: - return true; - - default: - case Host.LLAMA_CPP: - return false; + switch (host) + { + case Host.LM_STUDIO: + case Host.OLLAMA: + case Host.VLLM: + case Host.LLMMAN: + return true; + + default: + case Host.LLAMA_CPP: + return false; + } } } - public bool IsTranscriptionSupported() + public bool IsTranscriptionSupported { - switch (host) + get { - case Host.OLLAMA: - case Host.VLLM: - case Host.WHISPER_CPP: - case Host.LLMMAN: - return true; + switch (host) + { + case Host.OLLAMA: + case Host.VLLM: + case Host.WHISPER_CPP: + case Host.LLMMAN: + return true; - default: - case Host.LM_STUDIO: - case Host.LLAMA_CPP: - return false; + default: + case Host.LM_STUDIO: + case Host.LLAMA_CPP: + return false; + } } } @@ -122,22 +131,25 @@ public static class HostExtensions /// provider offers that model under a fixed name instead. llama.cpp is, even though builds /// older than the route answer it with 404; the provider handles those builds itself. /// - /// True when the models can be loaded from the engine; otherwise, false. - public bool IsModelListSupported() + /// True when the models can be loaded from the engine; otherwise, false. + public bool IsModelListSupported { - switch (host) + get { - case Host.LLAMA_CPP: - case Host.OLLAMA: - case Host.LM_STUDIO: - case Host.VLLM: - case Host.LLMMAN: - return true; + switch (host) + { + case Host.LLAMA_CPP: + case Host.OLLAMA: + case Host.LM_STUDIO: + case Host.VLLM: + case Host.LLMMAN: + return true; - default: - case Host.NONE: - case Host.WHISPER_CPP: - return false; + default: + case Host.NONE: + case Host.WHISPER_CPP: + return false; + } } } } diff --git a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs index 95a6ccc45..d26fcb84b 100644 --- a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs +++ b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs @@ -10,7 +10,7 @@ using AIStudio.Tools.PluginSystem; namespace AIStudio.Provider.SelfHosted; -public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvider(LLMProviders.SELF_HOSTED, new Uri($"{hostname}{host.BaseURL()}"), ExternalHttpTrustPolicy.ALLOW_CUSTOM_ROOTS_WHEN_HOST_WHITELISTED, LOGGER) +public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvider(LLMProviders.SELF_HOSTED, new Uri($"{hostname}{host.BaseURL}"), ExternalHttpTrustPolicy.ALLOW_CUSTOM_ROOTS_WHEN_HOST_WHITELISTED, LOGGER) { private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger(); @@ -19,13 +19,13 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide #region Implementation of IProvider /// - public override string Id => LLMProviders.SELF_HOSTED.ToSecretId(); + public override string Id => LLMProviders.SELF_HOSTED.SecretId; /// public override string InstanceName { get; set; } = "Self-hosted"; /// - public override bool HasModelLoadingCapability => host.IsModelListSupported(); + public override bool HasModelLoadingCapability => host.IsModelListSupported; /// public override async IAsyncEnumerable StreamChatCompletion(Provider.Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) @@ -63,7 +63,7 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide }; }, isTryingSecret: true, - requestPath: host.ChatURL(), + requestPath: host.ChatURL, token: token)) yield return content; } @@ -97,7 +97,7 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide if (host is Host.LLAMA_CPP) return await this.LoadLlamaCppTextModels(apiKeyProvisional, token); - if (!host.IsChatSupported() || !host.IsModelListSupported()) + if (!host.IsChatSupported || !host.IsModelListSupported) return ModelLoadResult.FromModels([]); var result = await this.LoadModels(SecretStoreType.LLM_PROVIDER, apiKeyProvisional, token); @@ -123,7 +123,7 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide { try { - if (!host.IsEmbeddingSupported() || !host.IsModelListSupported()) + if (!host.IsEmbeddingSupported || !host.IsModelListSupported) return ModelLoadResult.FromModels([]); var result = await this.LoadModels(SecretStoreType.EMBEDDING_PROVIDER, apiKeyProvisional, token); @@ -150,7 +150,7 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide new Provider.Model("loaded-model", TB("Model as configured by whisper.cpp")), ]); - if (!host.IsTranscriptionSupported() || !host.IsModelListSupported()) + if (!host.IsTranscriptionSupported || !host.IsModelListSupported) return ModelLoadResult.FromModels([]); // diff --git a/app/MindWork AI Studio/Provider/X/ProviderX.cs b/app/MindWork AI Studio/Provider/X/ProviderX.cs index b2227147a..ddbaeed22 100644 --- a/app/MindWork AI Studio/Provider/X/ProviderX.cs +++ b/app/MindWork AI Studio/Provider/X/ProviderX.cs @@ -13,7 +13,7 @@ public sealed class ProviderX() : BaseProvider(LLMProviders.X, new Uri("https:// #region Implementation of IProvider /// - public override string Id => LLMProviders.X.ToSecretId(); + public override string Id => LLMProviders.X.SecretId; /// public override string InstanceName { get; set; } = "xAI"; diff --git a/app/MindWork AI Studio/Settings/ChatTemplate.cs b/app/MindWork AI Studio/Settings/ChatTemplate.cs index 645c878cb..3affa0762 100644 --- a/app/MindWork AI Studio/Settings/ChatTemplate.cs +++ b/app/MindWork AI Studio/Settings/ChatTemplate.cs @@ -449,7 +449,7 @@ public record ChatTemplate( if (!optionsTable.TryGetValue("RetrievalMode", out var retrievalModeValue)) return DataSourceRetrievalMode.SEMANTIC_SEARCH; - if (retrievalModeValue.TryRead(out var retrievalModeText) && EnumNames.TryParse(retrievalModeText, out var retrievalMode)) + if (retrievalModeValue.TryRead(out var retrievalModeText) && DataSourceRetrievalMode.TryParseName(retrievalModeText, out var retrievalMode)) return retrievalMode; LOGGER.LogWarning("The RetrievalMode of chat template {IdxChatTemplate} is not one of {RetrievalModes}. The template uses semantic search instead.", idx, string.Join(", ", Enum.GetNames())); diff --git a/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs b/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs index 871bb743e..0de0745f1 100644 --- a/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs +++ b/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs @@ -25,7 +25,7 @@ public static class ConfigurationSelectDataFactory public static IEnumerable> GetLangBehaviorData() { foreach (var behavior in Enum.GetValues()) - yield return new(behavior.Name(), behavior); + yield return new(behavior.Name, behavior); } public static IEnumerable> GetLanguagesData() @@ -117,14 +117,14 @@ public static class ConfigurationSelectDataFactory public static IEnumerable> GetPreviewFeaturesData(SettingsManager settingsManager) { - foreach (var source in settingsManager.ConfigurationData.App.PreviewVisibility.GetPreviewFeatures().Where(x => !x.IsReleased())) - yield return new(source.GetPreviewDescription(), source); + foreach (var source in settingsManager.ConfigurationData.App.PreviewVisibility.GetPreviewFeatures().Where(x => !x.IsReleased)) + yield return new(source.PreviewDescription, source); } public static IEnumerable> GetSendToChatDataSourceBehaviorData() { foreach (var behavior in Enum.GetValues()) - yield return new(behavior.Description(), behavior); + yield return new(behavior.Description, behavior); } public static IEnumerable> GetNavBehaviorData() @@ -162,13 +162,13 @@ public static class ConfigurationSelectDataFactory public static IEnumerable> GetIconSourcesData() { foreach (var source in Enum.GetValues()) - yield return new(source.Name(), source); + yield return new(source.Name, source); } public static IEnumerable> GetCommonLanguagesData() { foreach (var language in Enum.GetValues()) - yield return new(language.Name(), language); + yield return new(language.Name, language); } public static IEnumerable> GetCommonLanguagesTranslationData() @@ -177,7 +177,7 @@ public static class ConfigurationSelectDataFactory if(language is CommonLanguages.AS_IS) yield return new(TB("Not yet specified"), language); else - yield return new(language.Name(), language); + yield return new(language.Name, language); } public static IEnumerable> GetCommonLanguagesOptionalData() @@ -186,73 +186,73 @@ public static class ConfigurationSelectDataFactory if(language is CommonLanguages.AS_IS) yield return new(TB("Do not specify the language"), language); else - yield return new(language.Name(), language); + yield return new(language.Name, language); } public static IEnumerable> GetCommonCodingLanguagesData() { foreach (var language in Enum.GetValues()) - yield return new(language.Name(), language); + yield return new(language.Name, language); } public static IEnumerable> GetComplexityData() { foreach (var complexity in Enum.GetValues()) - yield return new(complexity.Name(), complexity); + yield return new(complexity.Name, complexity); } public static IEnumerable> GetNumberParticipantsData() { foreach (var number in Enum.GetValues()) - yield return new(number.Name(), number); + yield return new(number.Name, number); } public static IEnumerable> GetWritingStyles4RewriteData() { foreach (var style in Enum.GetValues()) - yield return new(style.Name(), style); + yield return new(style.Name, style); } public static IEnumerable> GetWritingStyles4EMailData() { foreach (var style in Enum.GetValues()) - yield return new(style.Name(), style); + yield return new(style.Name, style); } public static IEnumerable> GetSentenceStructureData() { foreach (var voice in Enum.GetValues()) - yield return new(voice.Name(), voice); + yield return new(voice.Name, voice); } public static IEnumerable> GetSlideBuilderAudienceProfileData() { foreach (var profile in Enum.GetValues()) - yield return new(profile.Name(), profile); + yield return new(profile.Name, profile); } public static IEnumerable> GetSlideBuilderAudienceAgeGroupData() { foreach (var ageGroup in Enum.GetValues()) - yield return new(ageGroup.Name(), ageGroup); + yield return new(ageGroup.Name, ageGroup); } public static IEnumerable> GetSlideBuilderAudienceOrganizationalLevelData() { foreach (var level in Enum.GetValues()) - yield return new(level.Name(), level); + yield return new(level.Name, level); } public static IEnumerable> GetSlideBuilderAudienceExpertiseData() { foreach (var expertise in Enum.GetValues()) - yield return new(expertise.Name(), expertise); + yield return new(expertise.Name, expertise); } public static IEnumerable> GetSlideBuilderOccasionData() { foreach (var occasion in Enum.GetValues()) - yield return new(occasion.Name(), occasion); + yield return new(occasion.Name, occasion); } public static IEnumerable> GetProfilesData(IEnumerable profiles) @@ -285,7 +285,7 @@ public static class ConfigurationSelectDataFactory public static IEnumerable> GetConfidenceSchemesData() { foreach (var scheme in Enum.GetValues()) - yield return new(scheme.GetListDescription(), scheme); + yield return new(scheme.ListDescription, scheme); } public static IEnumerable> GetConfidenceLevelsData(SettingsManager settingsManager, bool restrictToGlobalMinimum = false) @@ -309,7 +309,7 @@ public static class ConfigurationSelectDataFactory continue; default: - yield return new(level.GetName(), level); + yield return new(level.Name, level); break; } } @@ -322,7 +322,7 @@ public static class ConfigurationSelectDataFactory if (level is ConfidenceLevel.NONE) continue; - yield return new(level.GetName(), level); + yield return new(level.Name, level); } } @@ -330,10 +330,10 @@ public static class ConfigurationSelectDataFactory { foreach (var level in Enum.GetValues()) { - if (!level.IsAllowedMailboxConfidence()) + if (!level.IsAllowedMailboxConfidence) continue; - yield return new(level.GetName(), level); + yield return new(level.Name, level); } } @@ -344,14 +344,14 @@ public static class ConfigurationSelectDataFactory if (transportSecurity is MailboxTransportSecurity.UNKNOWN) continue; - yield return new(transportSecurity.GetName(), transportSecurity); + yield return new(transportSecurity.Name, transportSecurity); } } public static IEnumerable> GetMailboxMaxAgeData() { foreach (var maxAge in Enum.GetValues()) - yield return new(maxAge.GetName(), maxAge); + yield return new(maxAge.Name, maxAge); } /// @@ -362,13 +362,13 @@ public static class ConfigurationSelectDataFactory { foreach (var restriction in Enum.GetValues()) if (restriction.StricterOf(minimumRestriction) == restriction) - yield return new(restriction.GetName(), restriction); + yield return new(restriction.Name, restriction); } public static IEnumerable> GetThemesData() { foreach (var theme in Enum.GetValues()) - yield return new(theme.GetName(), theme); + yield return new(theme.Name, theme); } public static IEnumerable> GetAssistantAuditLevelsData() @@ -378,7 +378,7 @@ public static class ConfigurationSelectDataFactory if (level == AssistantAuditLevel.UNKNOWN) continue; - yield return new(level.GetName(), level); + yield return new(level.Name, level); } } @@ -386,7 +386,7 @@ public static class ConfigurationSelectDataFactory { foreach (var bitrate in Enum.GetValues()) { - yield return new(bitrate.GetName(), bitrate); + yield return new(bitrate.Name, bitrate); } } diff --git a/app/MindWork AI Studio/Settings/DataModel/BiasCategoryExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/BiasCategoryExtensions.cs index e16e1e554..1648f3272 100644 --- a/app/MindWork AI Studio/Settings/DataModel/BiasCategoryExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/BiasCategoryExtensions.cs @@ -4,7 +4,7 @@ public static class BiasCategoryExtensions { extension(BiasCategory biasCategory) { - public string ToName() => biasCategory switch + public string Name => biasCategory switch { BiasCategory.WHAT_SHOULD_WE_REMEMBER => "What should we remember?", BiasCategory.TOO_MUCH_INFORMATION => "Too much information", @@ -14,7 +14,7 @@ public static class BiasCategoryExtensions _ => "Unknown category", }; - public string GetThoughts() => biasCategory switch + public string Thoughts => biasCategory switch { BiasCategory.WHAT_SHOULD_WE_REMEMBER => """ diff --git a/app/MindWork AI Studio/Settings/DataModel/DataBatchProcessing.cs b/app/MindWork AI Studio/Settings/DataModel/DataBatchProcessing.cs index d02c4f1ab..2dcb7b2ad 100644 --- a/app/MindWork AI Studio/Settings/DataModel/DataBatchProcessing.cs +++ b/app/MindWork AI Studio/Settings/DataModel/DataBatchProcessing.cs @@ -56,7 +56,7 @@ public sealed class DataBatchProcessing(Expression /// - /// Only formats which hold an entire answer, see FileExportFormatExtensions.ANSWER_FORMATS. + /// Only formats which hold an entire answer, see FileExportFormat.AnswerFormats. /// The tabular formats belong to the output mode TABLE_ONLY, which writes one table for the /// whole run instead of one file per document. /// @@ -70,7 +70,7 @@ public sealed class DataBatchProcessing(Expression - public static bool IsValidResultFileFormat(FileExportFormat format) => FileExportFormatExtensions.ANSWER_FORMATS.Contains(format); + public static bool IsValidResultFileFormat(FileExportFormat format) => FileExportFormat.AnswerFormats.Contains(format); public string CsvFileName { get; set; } = ManagedConfiguration.Register(configSelection, value => value.CsvFileName, string.Empty); diff --git a/app/MindWork AI Studio/Settings/DataModel/DataMailboxProvider.cs b/app/MindWork AI Studio/Settings/DataModel/DataMailboxProvider.cs index 13baabef9..5f9a2f3cc 100644 --- a/app/MindWork AI Studio/Settings/DataModel/DataMailboxProvider.cs +++ b/app/MindWork AI Studio/Settings/DataModel/DataMailboxProvider.cs @@ -94,13 +94,13 @@ public sealed record DataMailboxProvider : ILivePluginContent } var transportSecurity = MailboxTransportSecurity.SSL_ON_CONNECT; - if (table.TryGetValue("TransportSecurity", out var transportSecurityValue) && (!transportSecurityValue.TryRead(out var transportSecurityText) || !EnumNames.TryParse(transportSecurityText, out transportSecurity) || transportSecurity is MailboxTransportSecurity.UNKNOWN)) + if (table.TryGetValue("TransportSecurity", out var transportSecurityValue) && (!transportSecurityValue.TryRead(out var transportSecurityText) || !MailboxTransportSecurity.TryParseName(transportSecurityText, out transportSecurity) || transportSecurity is MailboxTransportSecurity.UNKNOWN)) { logger.LogWarning("The configured mailbox provider {ProviderIndex} does not contain a valid TransportSecurity field. Allowed values are SSL_ON_CONNECT and STARTTLS.", index); return false; } - var port = transportSecurity.GetUsualPort() ?? MailboxTransportSecurityExtensions.SSL_ON_CONNECT_PORT; + var port = transportSecurity.UsualPort ?? MailboxTransportSecurityExtensions.SSL_ON_CONNECT_PORT; if (table.TryGetValue("Port", out var portValue) && (!portValue.TryRead(out port) || port is < 1 or > 65535)) { logger.LogWarning("The configured mailbox provider {ProviderIndex} does not contain a valid Port field. The port must be a number from 1 to 65535.", index); diff --git a/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs b/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs index 426bad57e..4f91518d7 100644 --- a/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs +++ b/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs @@ -170,7 +170,7 @@ public record struct DataSourceERI_V1: IERIDataSource Path = eriContext.Path ?? string.Empty, Type = eriContext.ToRetrievalContentType(), Links = eriContext.Links ?? [], - Category = eriContext.Type.ToRetrievalContentCategory(), + Category = eriContext.Type.RetrievalContentCategory, SourceCategory = eriContext.Category ?? string.Empty, MatchedText = eriContext.MatchedContent ?? string.Empty, DataSourceName = eriContext.Name ?? string.Empty, @@ -185,7 +185,7 @@ public record struct DataSourceERI_V1: IERIDataSource Type = eriContext.ToRetrievalContentType(), Links = eriContext.Links ?? [], Source = eriContext.MatchedContent ?? string.Empty, - Category = eriContext.Type.ToRetrievalContentCategory(), + Category = eriContext.Type.RetrievalContentCategory, SourceCategory = eriContext.Category ?? string.Empty, SourceType = ContentImageSource.BASE64, DataSourceName = eriContext.Name ?? string.Empty, @@ -275,7 +275,7 @@ public record struct DataSourceERI_V1: IERIDataSource // its passages reach a chat, see DataSourceOutboundDataExtensions.GetEffectiveOutboundDataRestriction. // var outboundDataRestriction = DataSourceOutboundDataExtensions.DEFAULT_OUTBOUND_DATA_RESTRICTION; - if (table.TryGetValue("OutboundDataRestriction", out var outboundDataRestrictionValue) && !(outboundDataRestrictionValue.TryRead(out var outboundDataRestrictionText) && EnumNames.TryParse(outboundDataRestrictionText, out outboundDataRestriction))) + if (table.TryGetValue("OutboundDataRestriction", out var outboundDataRestrictionValue) && !(outboundDataRestrictionValue.TryRead(out var outboundDataRestrictionText) && OutboundDataRestriction.TryParseName(outboundDataRestrictionText, out outboundDataRestriction))) { LOGGER.LogWarning($"The configured data source {idx} does not contain a valid outbound data restriction, so the strictest one applies. (Plugin ID: {configPluginId})"); outboundDataRestriction = OutboundDataRestriction.ONLY_CONFIGURED_SERVICES; diff --git a/app/MindWork AI Studio/Settings/DataModel/DataSourceSecurityExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/DataSourceSecurityExtensions.cs index 42290910a..154a35229 100644 --- a/app/MindWork AI Studio/Settings/DataModel/DataSourceSecurityExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/DataSourceSecurityExtensions.cs @@ -8,7 +8,7 @@ public static class DataSourceSecurityExtensions extension(DataSourceSecurity security) { - public string ToSelectionText() => security switch + public string SelectionText => security switch { DataSourceSecurity.NOT_SPECIFIED => TB("Please select a security policy"), @@ -18,7 +18,7 @@ public static class DataSourceSecurityExtensions _ => TB("Unknown security policy") }; - public string ToInfoText() => security switch + public string InfoText => security switch { DataSourceSecurity.NOT_SPECIFIED => TB("The security of the data source is not specified yet. You cannot use this data source until you specify a security policy."), @@ -28,7 +28,7 @@ public static class DataSourceSecurityExtensions _ => TB("Unknown security policy") }; - public TextColor GetColor() => security switch + public TextColor Color => security switch { DataSourceSecurity.ALLOW_ANY => TextColor.WARN, DataSourceSecurity.SELF_HOSTED => TextColor.SUCCESS, diff --git a/app/MindWork AI Studio/Settings/DataModel/DataSourceTypeExtension.cs b/app/MindWork AI Studio/Settings/DataModel/DataSourceTypeExtension.cs index fd6c2f928..18e2fb6ab 100644 --- a/app/MindWork AI Studio/Settings/DataModel/DataSourceTypeExtension.cs +++ b/app/MindWork AI Studio/Settings/DataModel/DataSourceTypeExtension.cs @@ -15,8 +15,8 @@ public static class DataSourceTypeExtension /// /// Get the display name of the data source type. /// - /// The display name of the data source type. - public string GetDisplayName() => type switch + /// The display name of the data source type. + public string DisplayName => type switch { DataSourceType.LOCAL_FILE => TB("Local File"), DataSourceType.LOCAL_DIRECTORY => TB("Local Directory"), diff --git a/app/MindWork AI Studio/Settings/DataModel/LangBehaviorExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/LangBehaviorExtensions.cs index 920aa514e..ec2463d2b 100644 --- a/app/MindWork AI Studio/Settings/DataModel/LangBehaviorExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/LangBehaviorExtensions.cs @@ -8,7 +8,7 @@ public static class LangBehaviorExtensions extension(LangBehavior langBehavior) { - public string Name() => langBehavior switch + public string Name => langBehavior switch { LangBehavior.AUTO => TB("Choose the language automatically, based on your system language."), LangBehavior.MANUAL => TB("Choose the language manually."), diff --git a/app/MindWork AI Studio/Settings/DataModel/MailboxMaxAgeExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/MailboxMaxAgeExtensions.cs index 3312997d9..6825c227c 100644 --- a/app/MindWork AI Studio/Settings/DataModel/MailboxMaxAgeExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/MailboxMaxAgeExtensions.cs @@ -9,7 +9,7 @@ public static class MailboxMaxAgeExtensions /// The period. extension(MailboxMaxAge maxAge) { - public string GetName() => maxAge switch + public string Name => maxAge switch { MailboxMaxAge.LAST_3_MONTHS => TB("The last 3 months"), MailboxMaxAge.LAST_6_MONTHS => TB("The last 6 months"), diff --git a/app/MindWork AI Studio/Settings/DataModel/MailboxTransportSecurityExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/MailboxTransportSecurityExtensions.cs index 9300ffbee..39ba576ab 100644 --- a/app/MindWork AI Studio/Settings/DataModel/MailboxTransportSecurityExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/MailboxTransportSecurityExtensions.cs @@ -18,7 +18,7 @@ public static class MailboxTransportSecurityExtensions extension(MailboxTransportSecurity transportSecurity) { - public string GetName() => transportSecurity switch + public string Name => transportSecurity switch { MailboxTransportSecurity.SSL_ON_CONNECT => TB("TLS from the start (usually port 993)"), MailboxTransportSecurity.STARTTLS => TB("STARTTLS (usually port 143)"), @@ -29,8 +29,8 @@ public static class MailboxTransportSecurityExtensions /// /// The port the encryption usually comes with. /// - /// The port, or null when there is no usual one. - public int? GetUsualPort() => transportSecurity switch + /// The port, or null when there is no usual one. + public int? UsualPort => transportSecurity switch { MailboxTransportSecurity.SSL_ON_CONNECT => SSL_ON_CONNECT_PORT, MailboxTransportSecurity.STARTTLS => STARTTLS_PORT, diff --git a/app/MindWork AI Studio/Settings/DataModel/OutboundDataRequirementExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/OutboundDataRequirementExtensions.cs index f6365b9f1..3a0912502 100644 --- a/app/MindWork AI Studio/Settings/DataModel/OutboundDataRequirementExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/OutboundDataRequirementExtensions.cs @@ -25,13 +25,13 @@ public static class OutboundDataRequirementExtensions public string GetToolBlockedMessage(Data settings) => requirement.Origin switch { OutboundDataOrigin.MAILBOX => GetMailboxBlockedMessage(requirement, settings.Mailboxes), - OutboundDataOrigin.CONFLUENCE_WIKI => string.Format(TB("This chat holds content from your Confluence wiki, found while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), requirement.Restriction.GetName()), - OutboundDataOrigin.INTERNAL_WEB_PAGE => string.Format(TB("This chat holds content from an internal web page on '{0}', read while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), requirement.Reference, requirement.Restriction.GetName()), + OutboundDataOrigin.CONFLUENCE_WIKI => string.Format(TB("This chat holds content from your Confluence wiki, found while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), requirement.Restriction.Name), + OutboundDataOrigin.INTERNAL_WEB_PAGE => string.Format(TB("This chat holds content from an internal web page on '{0}', read while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), requirement.Reference, requirement.Restriction.Name), OutboundDataOrigin.DATA_SOURCE => GetDataSourceBlockedMessage(requirement, settings.DataSources), // NONE keeps no tool from running, since nothing restricts such a chat. What is left is an // origin this version does not know: - _ => string.Format(TB("This chat holds internal content, read while a chat was restricted to '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), requirement.Restriction.GetName()), + _ => string.Format(TB("This chat holds internal content, read while a chat was restricted to '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), requirement.Restriction.Name), }; } @@ -43,8 +43,8 @@ public static class OutboundDataRequirementExtensions .FirstOrDefault(); return string.IsNullOrWhiteSpace(mailboxName) - ? string.Format(TB("This chat holds content from a mailbox which has been removed since, read while its setting 'Where a chat may send data after reading mails' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), requirement.Restriction.GetName()) - : string.Format(TB("This chat holds content from the mailbox '{0}', read while its setting 'Where a chat may send data after reading mails' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), mailboxName, requirement.Restriction.GetName()); + ? string.Format(TB("This chat holds content from a mailbox which has been removed since, read while its setting 'Where a chat may send data after reading mails' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), requirement.Restriction.Name) + : string.Format(TB("This chat holds content from the mailbox '{0}', read while its setting 'Where a chat may send data after reading mails' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), mailboxName, requirement.Restriction.Name); } private static string GetDataSourceBlockedMessage(OutboundDataRequirement requirement, IEnumerable dataSources) @@ -55,7 +55,7 @@ public static class OutboundDataRequirementExtensions .FirstOrDefault(); return string.IsNullOrWhiteSpace(dataSourceName) - ? string.Format(TB("This chat holds content from a data source which has been removed since, found while its setting 'Where a chat may send data after reading this data source' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), requirement.Restriction.GetName()) - : string.Format(TB("This chat holds content from the data source '{0}', found while its setting 'Where a chat may send data after reading this data source' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), dataSourceName, requirement.Restriction.GetName()); + ? string.Format(TB("This chat holds content from a data source which has been removed since, found while its setting 'Where a chat may send data after reading this data source' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), requirement.Restriction.Name) + : string.Format(TB("This chat holds content from the data source '{0}', found while its setting 'Where a chat may send data after reading this data source' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."), dataSourceName, requirement.Restriction.Name); } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/DataModel/OutboundDataRestrictionExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/OutboundDataRestrictionExtensions.cs index 12c777422..e74ab3e01 100644 --- a/app/MindWork AI Studio/Settings/DataModel/OutboundDataRestrictionExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/OutboundDataRestrictionExtensions.cs @@ -35,7 +35,7 @@ public static class OutboundDataRestrictionExtensions /// The restriction itself, or the strictest one when this version does not know it. public OutboundDataRestriction OrStrictestWhenUnknown() => Enum.IsDefined(restriction) ? restriction : OutboundDataRestriction.ONLY_CONFIGURED_SERVICES; - public string GetName() => restriction switch + public string Name => restriction switch { OutboundDataRestriction.ONLY_CONFIGURED_SERVICES => TB("Only services configured in AI Studio"), OutboundDataRestriction.ONLY_LINKS_FROM_CHAT => TB("Configured services and addresses from the chat"), @@ -47,7 +47,7 @@ public static class OutboundDataRestrictionExtensions /// /// What a chat may still do on this level, once internal content entered it. /// - public string GetDescription() => restriction switch + public string Description => restriction switch { OutboundDataRestriction.ONLY_CONFIGURED_SERVICES => TB("The chat may only use services configured in AI Studio: your mailboxes, your data sources, your Confluence wiki, and the allowed private hosts of the tool 'Read Web Page'. It reads no other web pages, and it does not search the web."), OutboundDataRestriction.ONLY_LINKS_FROM_CHAT => TB("The chat may also read web pages whose addresses stand in the chat, written by you or returned by a tool, exactly as they stand there. It does not search the web, and the AI cannot choose addresses of its own outside the services configured in AI Studio."), diff --git a/app/MindWork AI Studio/Settings/DataModel/PreviewFeaturesExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/PreviewFeaturesExtensions.cs index 3e7fd1536..78a29bdb4 100644 --- a/app/MindWork AI Studio/Settings/DataModel/PreviewFeaturesExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/PreviewFeaturesExtensions.cs @@ -9,7 +9,7 @@ public static class PreviewFeaturesExtensions /// The preview feature to check. extension(PreviewFeatures feature) { - public string GetPreviewDescription() => feature switch + public string PreviewDescription => feature switch { PreviewFeatures.PRE_WRITER_MODE_2024 => TB("Writer Mode: Experiments about how to write long texts using AI"), PreviewFeatures.PRE_RAG_2024 => TB("RAG: Preview of our RAG implementation where you can refer your files or integrate enterprise data within your company"), @@ -32,8 +32,8 @@ public static class PreviewFeaturesExtensions /// This metadata is necessary because we cannot remove the enum values from the list. /// Otherwise, we could not deserialize old settings files that may contain these values. /// - /// True when the preview feature is released, false otherwise. - public bool IsReleased() => feature switch + /// True when the preview feature is released, false otherwise. + public bool IsReleased => feature switch { PreviewFeatures.PRE_READ_PDF_2025 => true, PreviewFeatures.PRE_PLUGINS_2025 => true, @@ -45,7 +45,7 @@ public static class PreviewFeaturesExtensions public bool IsEnabled(SettingsManager settingsManager) { - if(feature.IsReleased()) + if(feature.IsReleased) return true; return settingsManager.ConfigurationData.App.EnabledPreviewFeatures.Contains(feature); diff --git a/app/MindWork AI Studio/Settings/DataModel/SendToChatDataSourceBehaviorExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/SendToChatDataSourceBehaviorExtensions.cs index a04c95d1d..ac05913b7 100644 --- a/app/MindWork AI Studio/Settings/DataModel/SendToChatDataSourceBehaviorExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/SendToChatDataSourceBehaviorExtensions.cs @@ -8,7 +8,7 @@ public static class SendToChatDataSourceBehaviorExtensions extension(SendToChatDataSourceBehavior behavior) { - public string Description() => behavior switch + public string Description => behavior switch { SendToChatDataSourceBehavior.NO_DATA_SOURCES => TB("Use no data sources, when sending an assistant result to a chat"), SendToChatDataSourceBehavior.APPLY_STANDARD_CHAT_DATA_SOURCE_OPTIONS => TB("Apply standard chat data source options, when sending an assistant result to a chat"), diff --git a/app/MindWork AI Studio/Settings/DataModel/StartPageExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/StartPageExtensions.cs index 1edce9840..af545dc27 100644 --- a/app/MindWork AI Studio/Settings/DataModel/StartPageExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/StartPageExtensions.cs @@ -4,7 +4,7 @@ public static class StartPageExtensions { extension(StartPage startPage) { - public string ToRoute() => startPage switch + public string Route => startPage switch { StartPage.HOME => string.Empty, StartPage.CHAT => Routes.CHAT, diff --git a/app/MindWork AI Studio/Settings/DataModel/ThemesExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/ThemesExtensions.cs index b3c038bec..d5559a96f 100644 --- a/app/MindWork AI Studio/Settings/DataModel/ThemesExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/ThemesExtensions.cs @@ -8,7 +8,7 @@ public static class ThemesExtensions extension(Themes theme) { - public string GetName() => theme switch + public string Name => theme switch { Themes.SYSTEM => TB("Synchronized with the operating system settings"), Themes.LIGHT => TB("Always use light theme"), diff --git a/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrateExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrateExtensions.cs index 6ca58727d..9d411ada5 100644 --- a/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrateExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrateExtensions.cs @@ -8,7 +8,7 @@ public static class TranscriptionOpusBitrateExtensions extension(TranscriptionOpusBitrate bitrate) { - public string GetName() => bitrate switch + public string Name => bitrate switch { TranscriptionOpusBitrate.KBPS_32 => TB("32 kbps (smallest upload, lowest accuracy)"), TranscriptionOpusBitrate.KBPS_64 => TB("64 kbps"), @@ -17,7 +17,7 @@ public static class TranscriptionOpusBitrateExtensions _ => TB("Unknown"), }; - public uint GetBitsPerSecond() => bitrate switch + public uint BitsPerSecond => bitrate switch { TranscriptionOpusBitrate.KBPS_32 => 32_000, TranscriptionOpusBitrate.KBPS_64 => 64_000, diff --git a/app/MindWork AI Studio/Settings/DataSourceSecurityTrustExtensions.cs b/app/MindWork AI Studio/Settings/DataSourceSecurityTrustExtensions.cs index b4032dfbe..cfbf0d1ca 100644 --- a/app/MindWork AI Studio/Settings/DataSourceSecurityTrustExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataSourceSecurityTrustExtensions.cs @@ -136,7 +136,7 @@ public static class DataSourceSecurityTrustExtensions /// public bool AllowsMailboxConfidenceLevel(ConfidenceLevel mailboxConfidenceLevel) { - if (!mailboxConfidenceLevel.IsAllowedMailboxConfidence()) + if (!mailboxConfidenceLevel.IsAllowedMailboxConfidence) return false; return providerConfidenceLevel >= mailboxConfidenceLevel; @@ -153,7 +153,7 @@ public static class DataSourceSecurityTrustExtensions /// AllowsDataSourceConfidenceLevel, and UNTRUSTED and UNKNOWN do almost the same: both lie at or /// below the level of a provider nobody rated, so even such a provider would meet them. /// - public bool IsAllowedMailboxConfidence() => confidenceLevel is ConfidenceLevel.VERY_LOW or ConfidenceLevel.LOW or ConfidenceLevel.MODERATE or ConfidenceLevel.MEDIUM or ConfidenceLevel.HIGH; + public bool IsAllowedMailboxConfidence => confidenceLevel is ConfidenceLevel.VERY_LOW or ConfidenceLevel.LOW or ConfidenceLevel.MODERATE or ConfidenceLevel.MEDIUM or ConfidenceLevel.HIGH; } extension(IEnumerable dataSources) diff --git a/app/MindWork AI Studio/Settings/EmbeddingProvider.cs b/app/MindWork AI Studio/Settings/EmbeddingProvider.cs index 430134b4d..596c737aa 100644 --- a/app/MindWork AI Studio/Settings/EmbeddingProvider.cs +++ b/app/MindWork AI Studio/Settings/EmbeddingProvider.cs @@ -77,7 +77,7 @@ public sealed record EmbeddingProvider( /// [JsonIgnore] - public string SecretId => this.IsEnterpriseConfiguration ? $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{this.UsedLLMProvider.ToSecretId()}" : this.UsedLLMProvider.ToSecretId(); + public string SecretId => this.IsEnterpriseConfiguration ? $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{this.UsedLLMProvider.SecretId}" : this.UsedLLMProvider.SecretId; /// [JsonIgnore] @@ -226,7 +226,7 @@ public sealed record EmbeddingProvider( if (!dryRun) { PendingEnterpriseApiKeys.Add(new( - $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{usedLLMProvider.ToSecretId()}", + $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{usedLLMProvider.SecretId}", name, decryptedApiKey, SecretStoreType.EMBEDDING_PROVIDER)); diff --git a/app/MindWork AI Studio/Settings/EnumNames.cs b/app/MindWork AI Studio/Settings/EnumNames.cs index 6af4d9b22..1a7230f06 100644 --- a/app/MindWork AI Studio/Settings/EnumNames.cs +++ b/app/MindWork AI Studio/Settings/EnumNames.cs @@ -16,23 +16,32 @@ namespace AIStudio.Settings; /// public static class EnumNames { - /// - /// Reads the name of a member of the given enum. - /// - /// The text to read. - /// The member named, or the default when the text names none. /// The enum to read a member of. - /// True when the text names exactly one member. - public static bool TryParse(string? text, out TEnum value) where TEnum : struct, Enum + extension(TEnum) where TEnum : struct, Enum { - if (TryParse(typeof(TEnum), text, out var member)) + /// + /// Reads the name of a member of the enum. + /// + /// + /// Named TryParseName rather than TryParse: Enum.TryParse is reached through every enum as + /// well, and C# prefers it over an extension member of the same name. Code which knows the + /// enum only as a type parameter writes EnumNames.TryParseName<TEnum>(…), since C# looks + /// up no static member on a type parameter. + /// + /// The text to read. + /// The member named, or the default when the text names none. + /// True when the text names exactly one member. + public static bool TryParseName(string? text, out TEnum value) { - value = (TEnum)member; - return true; - } + if (TryParse(typeof(TEnum), text, out var member)) + { + value = (TEnum)member; + return true; + } - value = default; - return false; + value = default; + return false; + } } /// diff --git a/app/MindWork AI Studio/Settings/ManagedConfiguration.Parsing.cs b/app/MindWork AI Studio/Settings/ManagedConfiguration.Parsing.cs index 479b49352..b72850146 100644 --- a/app/MindWork AI Studio/Settings/ManagedConfiguration.Parsing.cs +++ b/app/MindWork AI Studio/Settings/ManagedConfiguration.Parsing.cs @@ -909,8 +909,8 @@ public static partial class ManagedConfiguration // If both key and value were read successfully, parse and add them to the dictionary: if (hadKey && hadValue - && EnumNames.TryParse(keyText, out var key) - && EnumNames.TryParse(valueText, out var value)) + && EnumNames.TryParseName(keyText, out var key) + && EnumNames.TryParseName(valueText, out var value)) configuredValue[key] = value; } @@ -982,7 +982,7 @@ public static partial class ManagedConfiguration var hadValue = pair.Value.TryRead(out var valueText); // If both were read successfully and the key names a member of the enum, add them to the dictionary: - if (hadKey && hadValue && EnumNames.TryParse(keyText, out var key)) + if (hadKey && hadValue && EnumNames.TryParseName(keyText, out var key)) configuredValue[key] = valueText; } @@ -1056,7 +1056,7 @@ public static partial class ManagedConfiguration var hadValue = pair.Value.TryRead(out var valueText); // If both were read successfully and the value names a member of the enum, add them to the dictionary: - if (hadKey && hadValue && EnumNames.TryParse(valueText, out var value)) + if (hadKey && hadValue && EnumNames.TryParseName(valueText, out var value)) configuredValue[key] = value; // A dry run comes before the actual one, so only the actual one reports the entry: diff --git a/app/MindWork AI Studio/Settings/Provider.cs b/app/MindWork AI Studio/Settings/Provider.cs index 601f8a71d..318b775b4 100644 --- a/app/MindWork AI Studio/Settings/Provider.cs +++ b/app/MindWork AI Studio/Settings/Provider.cs @@ -89,9 +89,9 @@ public sealed record Provider( public override string ToString() { if(this.IsSelfHosted) - return $"{this.InstanceName} ({this.UsedLLMProvider.ToName()}, {this.Host}, {this.Hostname}, {this.Model})"; + return $"{this.InstanceName} ({this.UsedLLMProvider.Name}, {this.Host}, {this.Hostname}, {this.Model})"; - return $"{this.InstanceName} ({this.UsedLLMProvider.ToName()}, {this.Model})"; + return $"{this.InstanceName} ({this.UsedLLMProvider.Name}, {this.Model})"; } #endregion @@ -100,7 +100,7 @@ public sealed record Provider( /// [JsonIgnore] - public string SecretId => this.IsEnterpriseConfiguration ? $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{this.UsedLLMProvider.ToSecretId()}" : this.UsedLLMProvider.ToSecretId(); + public string SecretId => this.IsEnterpriseConfiguration ? $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{this.UsedLLMProvider.SecretId}" : this.UsedLLMProvider.SecretId; /// [JsonIgnore] @@ -247,7 +247,7 @@ public sealed record Provider( if (!dryRun) { PendingEnterpriseApiKeys.Add(new( - $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{usedLLMProvider.ToSecretId()}", + $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{usedLLMProvider.SecretId}", instanceName, decryptedApiKey, SecretStoreType.LLM_PROVIDER)); diff --git a/app/MindWork AI Studio/Settings/SettingsManager.cs b/app/MindWork AI Studio/Settings/SettingsManager.cs index 3c4d7c418..6a4a82962 100644 --- a/app/MindWork AI Studio/Settings/SettingsManager.cs +++ b/app/MindWork AI Studio/Settings/SettingsManager.cs @@ -697,7 +697,7 @@ public sealed class SettingsManager /// /// All configured providers, unfiltered. public IReadOnlyList GetAllProviders() => this.ConfigurationData.Providers - .OrderBy(x => x.UsedLLMProvider.ToName(), StringComparer.OrdinalIgnoreCase) + .OrderBy(x => x.UsedLLMProvider.Name, StringComparer.OrdinalIgnoreCase) .ThenBy(x => x.InstanceName, StringComparer.OrdinalIgnoreCase) .ThenBy(x => x.Num) .ToList(); @@ -821,7 +821,7 @@ public sealed class SettingsManager /// /// All configured embedding providers. public IReadOnlyList GetAllEmbeddingProviders() => this.ConfigurationData.EmbeddingProviders - .OrderBy(x => x.UsedLLMProvider.ToName(), StringComparer.OrdinalIgnoreCase) + .OrderBy(x => x.UsedLLMProvider.Name, StringComparer.OrdinalIgnoreCase) .ThenBy(x => x.Name, StringComparer.OrdinalIgnoreCase) .ThenBy(x => x.Num) .ToList(); @@ -859,7 +859,7 @@ public sealed class SettingsManager /// /// All configured transcription providers. public IReadOnlyList GetAllTranscriptionProviders() => this.ConfigurationData.TranscriptionProviders - .OrderBy(x => x.UsedLLMProvider.ToName(), StringComparer.OrdinalIgnoreCase) + .OrderBy(x => x.UsedLLMProvider.Name, StringComparer.OrdinalIgnoreCase) .ThenBy(x => x.Name, StringComparer.OrdinalIgnoreCase) .ThenBy(x => x.Num) .ToList(); diff --git a/app/MindWork AI Studio/Settings/TranscriptionProvider.cs b/app/MindWork AI Studio/Settings/TranscriptionProvider.cs index 7473720f7..4b3eb62f6 100644 --- a/app/MindWork AI Studio/Settings/TranscriptionProvider.cs +++ b/app/MindWork AI Studio/Settings/TranscriptionProvider.cs @@ -70,7 +70,7 @@ public sealed record TranscriptionProvider( /// [JsonIgnore] - public string SecretId => this.IsEnterpriseConfiguration ? $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{this.UsedLLMProvider.ToSecretId()}" : this.UsedLLMProvider.ToSecretId(); + public string SecretId => this.IsEnterpriseConfiguration ? $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{this.UsedLLMProvider.SecretId}" : this.UsedLLMProvider.SecretId; /// [JsonIgnore] @@ -189,7 +189,7 @@ public sealed record TranscriptionProvider( if (!dryRun) { PendingEnterpriseApiKeys.Add(new( - $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{usedLLMProvider.ToSecretId()}", + $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{usedLLMProvider.SecretId}", name, decryptedApiKey, SecretStoreType.TRANSCRIPTION_PROVIDER)); diff --git a/app/MindWork AI Studio/Tools/AppUserAgent.cs b/app/MindWork AI Studio/Tools/AppUserAgent.cs index b5c19bd52..29b13d75b 100644 --- a/app/MindWork AI Studio/Tools/AppUserAgent.cs +++ b/app/MindWork AI Studio/Tools/AppUserAgent.cs @@ -38,7 +38,7 @@ public static class AppUserAgent /// The settings, which say whether the user shares the feature usage. /// True when the provider runs on a self-hosted server and sharing is switched on; otherwise, false. public static bool IsAllowedFor(LLMProviders provider, SettingsManager settingsManager) => - provider.RunsOnSelfHostedServer() && settingsManager.ConfigurationData.App.ShareFeatureUsageWithSelfHostedServerOperators; + provider.RunsOnSelfHostedServer && settingsManager.ConfigurationData.App.ShareFeatureUsageWithSelfHostedServerOperators; /// /// Sets the User-Agent as default header of the given HTTP client. @@ -109,7 +109,7 @@ public static class AppUserAgent private static string CreateBase() { - var rid = RIDExtensions.GetCurrentRID().AsMicrosoftRid(); + var rid = RID.Current.MicrosoftRid; return string.IsNullOrWhiteSpace(rid) ? $"MindWorkAIStudio/{META_DATA.Version}" : $"MindWorkAIStudio/{META_DATA.Version} ({rid})"; diff --git a/app/MindWork AI Studio/Tools/AssistantCategoryExtensions.cs b/app/MindWork AI Studio/Tools/AssistantCategoryExtensions.cs index 92e6b4a27..2464fa9af 100644 --- a/app/MindWork AI Studio/Tools/AssistantCategoryExtensions.cs +++ b/app/MindWork AI Studio/Tools/AssistantCategoryExtensions.cs @@ -8,7 +8,7 @@ public static class AssistantCategoryExtensions extension(AssistantCategory category) { - public string Name() => category switch + public string Name => category switch { AssistantCategory.AS_IS => TB("Select the assistant category"), AssistantCategory.GENERAL => TB("General"), @@ -23,12 +23,15 @@ public static class AssistantCategoryExtensions _ => string.Empty, }; - public string NameSelecting() + public string NameSelecting { - if(category is AssistantCategory.AS_IS) - return TB("Please select the assistant category"); + get + { + if(category is AssistantCategory.AS_IS) + return TB("Please select the assistant category"); - return category.Name(); + return category.Name; + } } } } diff --git a/app/MindWork AI Studio/Tools/AssistantLaunch/AssistantLaunchService.cs b/app/MindWork AI Studio/Tools/AssistantLaunch/AssistantLaunchService.cs index ca912b596..76dab8fbc 100644 --- a/app/MindWork AI Studio/Tools/AssistantLaunch/AssistantLaunchService.cs +++ b/app/MindWork AI Studio/Tools/AssistantLaunch/AssistantLaunchService.cs @@ -91,7 +91,7 @@ public sealed class AssistantLaunchService(SettingsManager settingsManager, Assi public async Task LaunchAsync(Components destination, TextLaunchPayload payload) { var route = destination.GetData().Route; - if (destination.HasSingleSessionSlot() && assistantSessionService.GetSnapshots().Any(snapshot => snapshot.IsActive && snapshot.Key.Component == destination)) + if (destination.HasSingleSessionSlot && assistantSessionService.GetSnapshots().Any(snapshot => snapshot.IsActive && snapshot.Key.Component == destination)) { await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.Apps, TB("This assistant is already running. AI Studio opens the running session instead."))); navigationManager.NavigateTo(route); @@ -101,7 +101,7 @@ public sealed class AssistantLaunchService(SettingsManager settingsManager, Assi // Only components with a single session slot may be cleared as a group. The visual briefing // assistant keys its sessions per briefing, so clearing by component would discard the // status of every stored briefing instead of the one we are about to open. - if (destination.HasSingleSessionSlot()) + if (destination.HasSingleSessionSlot) await assistantSessionService.ClearInactiveSessionsForComponentAsync(destination); MessageBus.INSTANCE.DeferMessage(null, TextEventFor(destination), payload); @@ -117,7 +117,7 @@ public sealed class AssistantLaunchService(SettingsManager settingsManager, Assi /// /// The component which opens. /// The text sent, or null when nothing was sent to the component. - public static TextLaunchPayload? TakeTextPayload(Components destination) => destination.AllowSendTo() + public static TextLaunchPayload? TakeTextPayload(Components destination) => destination.AllowSendTo ? MessageBus.INSTANCE.TakeDeferredMessages(TextEventFor(destination)).LastOrDefault() : null; @@ -146,11 +146,11 @@ public sealed class AssistantLaunchService(SettingsManager settingsManager, Assi /// Whether the user sees the given assistant at all. /// The destinations the user can choose from. internal static IReadOnlyList SelectDestinations(Components sender, Func isVisible) => Enum.GetValues() - .Where(destination => destination.AllowSendTo()) + .Where(destination => destination.AllowSendTo) .Where(destination => destination != sender || destination is Components.CHAT) .Where(isVisible) - .OrderBy(destination => destination.Name().Length) + .OrderBy(destination => destination.Name.Length) .ToArray(); - private bool IsVisible(Components destination) => settingsManager.IsAssistantVisible(destination, withLogging: false, requiredPreviewFeature: destination.RequiredPreviewFeature()); + private bool IsVisible(Components destination) => settingsManager.IsAssistantVisible(destination, withLogging: false, requiredPreviewFeature: destination.RequiredPreviewFeature); } diff --git a/app/MindWork AI Studio/Tools/AuthMethodsV1Extensions.cs b/app/MindWork AI Studio/Tools/AuthMethodsV1Extensions.cs index 1496be1d2..b6c84d734 100644 --- a/app/MindWork AI Studio/Tools/AuthMethodsV1Extensions.cs +++ b/app/MindWork AI Studio/Tools/AuthMethodsV1Extensions.cs @@ -9,7 +9,7 @@ public static class AuthMethodsV1Extensions extension(AuthMethod authMethod) { - public string DisplayName() => authMethod switch + public string DisplayName => authMethod switch { AuthMethod.NONE => TB("None"), AuthMethod.USERNAME_PASSWORD => TB("Username & Password"), diff --git a/app/MindWork AI Studio/Tools/CodeHighlighting/CodeTokenKindExtensions.cs b/app/MindWork AI Studio/Tools/CodeHighlighting/CodeTokenKindExtensions.cs index 4a2a35196..e3966bb03 100644 --- a/app/MindWork AI Studio/Tools/CodeHighlighting/CodeTokenKindExtensions.cs +++ b/app/MindWork AI Studio/Tools/CodeHighlighting/CodeTokenKindExtensions.cs @@ -9,8 +9,8 @@ public static class CodeTokenKindExtensions /// The CSS class which MudBlazor.Markdown gives this kind of part, so that it takes its color from /// the palette of the theme, just as the languages the library highlights itself. /// - /// The CSS class of the part. - public string ToCssClass() => kind switch + /// The CSS class of the part. + public string CssClass => kind switch { CodeTokenKind.KEYWORD => "hljs-keyword", CodeTokenKind.TYPE => "hljs-type", diff --git a/app/MindWork AI Studio/Tools/CommonLanguageExtensions.cs b/app/MindWork AI Studio/Tools/CommonLanguageExtensions.cs index 4151eafc4..2d04ba1cc 100644 --- a/app/MindWork AI Studio/Tools/CommonLanguageExtensions.cs +++ b/app/MindWork AI Studio/Tools/CommonLanguageExtensions.cs @@ -8,7 +8,7 @@ public static class CommonLanguageExtensions extension(CommonLanguages language) { - public string Name() => language switch + public string Name => language switch { CommonLanguages.AS_IS => TB("Do not change the language"), @@ -27,7 +27,7 @@ public static class CommonLanguageExtensions _ => TB("Other"), }; - public string ToIETFTag() => language switch + public string IETFTag => language switch { CommonLanguages.AS_IS => string.Empty, @@ -51,14 +51,14 @@ public static class CommonLanguageExtensions CommonLanguages.AS_IS => "Use the language the text is written in for the summary.", CommonLanguages.OTHER => $"Output your summary in {customLanguage}.", - _ => $"Output your summary in {language.Name()} ({language}).", + _ => $"Output your summary in {language.Name} ({language}).", }; public string PromptTranslation(string customLanguage) => language switch { CommonLanguages.OTHER => $"Translate the source text to {customLanguage}.", - _ => $"Translate the source text to {language.Name()} ({language}).", + _ => $"Translate the source text to {language.Name} ({language}).", }; public string PromptGeneralPurpose(string customLanguage) => language switch @@ -66,23 +66,29 @@ public static class CommonLanguageExtensions CommonLanguages.AS_IS => "Use the language the user input is written in for the output.", CommonLanguages.OTHER => $"use the language {customLanguage} for your output.", - _ => $"Use the language {language.Name()} ({language}) for your output.", + _ => $"Use the language {language.Name} ({language}) for your output.", }; - public string NameSelecting() + public string NameSelecting { - if(language is CommonLanguages.AS_IS) - return TB("Please select the target language"); - - return language.Name(); + get + { + if(language is CommonLanguages.AS_IS) + return TB("Please select the target language"); + + return language.Name; + } } - public string NameSelectingOptional() + public string NameSelectingOptional { - if(language is CommonLanguages.AS_IS) - return TB("Do not specify the language"); - - return language.Name(); + get + { + if(language is CommonLanguages.AS_IS) + return TB("Do not specify the language"); + + return language.Name; + } } } } diff --git a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs index 0ab13fe95..11efdb1bf 100644 --- a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs +++ b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs @@ -18,8 +18,8 @@ public static class ComponentsExtensions /// return . This is the single place that maps a component to /// its preview feature, so visibility checks never need to special-case one assistant. /// - /// The required preview feature. - public PreviewFeatures RequiredPreviewFeature() => component switch + /// The required preview feature. + public PreviewFeatures RequiredPreviewFeature => component switch { Components.VISUAL_BRIEFING_ASSISTANT => PreviewFeatures.PRE_VISUAL_BRIEFING_ASSISTANT_2026, @@ -37,8 +37,8 @@ public static class ComponentsExtensions /// component. All must be excluded from the single-slot checks, which is why this is a /// capability and not a component comparison. /// - /// true when the component owns exactly one session slot. - public bool HasSingleSessionSlot() => component switch + /// true when the component owns exactly one session slot. + public bool HasSingleSessionSlot => component switch { Components.CHAT or Components.DYNAMIC_ASSISTANT => false, Components.VISUAL_BRIEFING_ASSISTANT => false, @@ -49,15 +49,15 @@ public static class ComponentsExtensions /// /// Gets the kind of media-import owner a component creates for its attachments. /// - /// The media-import owner kind. - public MediaImportOwnerKind MediaOwnerKind() => component switch + /// The media-import owner kind. + public MediaImportOwnerKind MediaOwnerKind => component switch { Components.VISUAL_BRIEFING_ASSISTANT => MediaImportOwnerKind.VISUAL_BRIEFING, _ => MediaImportOwnerKind.ASSISTANT, }; - public bool AllowSendTo() => component switch + public bool AllowSendTo => component switch { Components.NONE => false, Components.DYNAMIC_ASSISTANT => false, @@ -81,7 +81,7 @@ public static class ComponentsExtensions _ => true, }; - public string Name() => component switch + public string Name => component switch { Components.GRAMMAR_SPELLING_ASSISTANT => TB("Grammar & Spelling Assistant"), Components.TEXT_SUMMARIZER_ASSISTANT => TB("Text Summarizer Assistant"), diff --git a/app/MindWork AI Studio/Tools/ConfidenceSchemesExtensions.cs b/app/MindWork AI Studio/Tools/ConfidenceSchemesExtensions.cs index e656e4881..9d9d016d0 100644 --- a/app/MindWork AI Studio/Tools/ConfidenceSchemesExtensions.cs +++ b/app/MindWork AI Studio/Tools/ConfidenceSchemesExtensions.cs @@ -8,7 +8,7 @@ public static class ConfidenceSchemesExtensions extension(ConfidenceSchemes scheme) { - public string GetListDescription() => scheme switch + public string ListDescription => scheme switch { ConfidenceSchemes.TRUST_ALL => TB("Trust all LLM providers"), ConfidenceSchemes.TRUST_USA_EUROPE => TB("Trust LLM providers from the USA and Europe"), diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/ProviderTypeExtensions.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/ProviderTypeExtensions.cs index b4147de75..bf20d6c6d 100644 --- a/app/MindWork AI Studio/Tools/ERIClient/DataModel/ProviderTypeExtensions.cs +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/ProviderTypeExtensions.cs @@ -8,7 +8,7 @@ public static class ProviderTypeExtensions extension(ProviderType providerType) { - public string Explain() => providerType switch + public string Explanation => providerType switch { ProviderType.NONE => TB("The related data is not allowed to be sent to any LLM provider. This means that this data source cannot be used at the moment."), ProviderType.ANY => TB("The related data can be sent to any provider, regardless of where it is hosted (cloud or self-hosted)."), diff --git a/app/MindWork AI Studio/Tools/FileExportFormatExtensions.cs b/app/MindWork AI Studio/Tools/FileExportFormatExtensions.cs index 9a15ff21d..2dc2a9505 100644 --- a/app/MindWork AI Studio/Tools/FileExportFormatExtensions.cs +++ b/app/MindWork AI Studio/Tools/FileExportFormatExtensions.cs @@ -23,43 +23,49 @@ public static class FileExportFormatExtensions private static readonly Encoding WITH_BYTE_ORDER_MARK = new UTF8Encoding(true); private static readonly Encoding WITHOUT_BYTE_ORDER_MARK = new UTF8Encoding(false); - /// - /// The formats which lay the text out as a document you would hand to somebody, in the order - /// the export menu shows them. - /// - public static readonly IReadOnlyList DOCUMENT_FORMATS = + private static readonly IReadOnlyList DOCUMENT_FORMATS = [ FileExportFormat.MICROSOFT_WORD, FileExportFormat.OPEN_DOCUMENT_TEXT, FileExportFormat.LATEX, ]; - /// - /// The formats which keep the text as text, in the order the export menu shows them. - /// - public static readonly IReadOnlyList TEXT_FORMATS = + private static readonly IReadOnlyList TEXT_FORMATS = [ FileExportFormat.MARKDOWN, FileExportFormat.HTML, ]; - /// - /// Every format an entire answer can be written as. - /// - /// - /// The tabular formats are missing on purpose: they hold one table out of an answer, never the - /// answer itself. Whoever offers a table adds them. - /// - public static readonly IReadOnlyList ANSWER_FORMATS = [..DOCUMENT_FORMATS, ..TEXT_FORMATS]; + private static readonly IReadOnlyList ANSWER_FORMATS = [..DOCUMENT_FORMATS, ..TEXT_FORMATS]; /// The format. extension(FileExportFormat format) { + /// + /// The formats which lay the text out as a document you would hand to somebody, in the order + /// the export menu shows them. + /// + public static IReadOnlyList DocumentFormats => DOCUMENT_FORMATS; + + /// + /// The formats which keep the text as text, in the order the export menu shows them. + /// + public static IReadOnlyList TextFormats => TEXT_FORMATS; + + /// + /// Every format an entire answer can be written as. + /// + /// + /// The tabular formats are missing on purpose: they hold one table out of an answer, never the + /// answer itself. Whoever offers a table adds them. + /// + public static IReadOnlyList AnswerFormats => ANSWER_FORMATS; + /// /// Returns the name of the format as shown to the user. /// - /// The name of the format. - public string ToName() => format switch + /// The name of the format. + public string Name => format switch { FileExportFormat.MICROSOFT_WORD => TB("Microsoft Word (.docx)"), FileExportFormat.OPEN_DOCUMENT_TEXT => TB("OpenDocument Text (.odt), e.g. LibreOffice"), @@ -76,8 +82,8 @@ public static class FileExportFormatExtensions /// /// Returns the icon of the format. /// - /// The icon of the format. - public string ToIcon() => format switch + /// The icon of the format. + public string Icon => format switch { FileExportFormat.MICROSOFT_WORD => Icons.Custom.FileFormats.FileWord, FileExportFormat.OPEN_DOCUMENT_TEXT => Icons.Custom.FileFormats.FileDocument, @@ -93,9 +99,9 @@ public static class FileExportFormatExtensions /// /// Returns the file extension of the format, including the leading dot. /// - /// The file extension, or an empty string when the format writes no file or, as code - /// does, takes the extension from its language. - public string ToFileExtension() => format switch + /// The file extension, or an empty string when the format writes no file or, as code + /// does, takes the extension from its language. + public string FileExtension => format switch { FileExportFormat.MICROSOFT_WORD => ".docx", FileExportFormat.OPEN_DOCUMENT_TEXT => ".odt", @@ -111,8 +117,8 @@ public static class FileExportFormatExtensions /// /// Determines whether the format holds a table rather than a text. /// - /// True for the formats a spreadsheet opens. - public bool IsTabular() => format is FileExportFormat.CSV or FileExportFormat.TSV; + /// True for the formats a spreadsheet opens. + public bool IsTabular => format is FileExportFormat.CSV or FileExportFormat.TSV; /// /// Determines whether a file of the format is plain text, which AI Studio writes as it is. @@ -124,8 +130,8 @@ public static class FileExportFormatExtensions /// list is spelled out on purpose, so a format added later counts as plain text only once /// somebody says so. /// - /// True, when a text written as it is makes a valid file of the format. - public bool IsPlainText() => format is FileExportFormat.LATEX or FileExportFormat.MARKDOWN or FileExportFormat.HTML or FileExportFormat.CSV or FileExportFormat.TSV or FileExportFormat.SOURCE_CODE; + /// True, when a text written as it is makes a valid file of the format. + public bool IsPlainText => format is FileExportFormat.LATEX or FileExportFormat.MARKDOWN or FileExportFormat.HTML or FileExportFormat.CSV or FileExportFormat.TSV or FileExportFormat.SOURCE_CODE; /// /// Returns the file name the save dialog starts with. @@ -138,14 +144,14 @@ public static class FileExportFormatExtensions /// What the file is about, for example the heading above a table. Anything /// a file name cannot hold is removed. Null or blank falls back to a generic name. /// The suggested file name, including its extension. - public string ToSuggestedFileName(string? name = null) => SuggestFileName(name, format.ToFileExtension()); + public string ToSuggestedFileName(string? name = null) => SuggestFileName(name, format.FileExtension); /// /// Returns the filter which the save dialog offers for the format. /// - /// The filter, or null when the format cannot be written or, as code does, takes the - /// filter from its language. - public FileTypeFilter? ToFileTypeFilter() => format switch + /// The filter, or null when the format cannot be written or, as code does, takes the + /// filter from its language. + public FileTypeFilter? FileTypeFilter => format switch { FileExportFormat.MICROSOFT_WORD => FileTypes.MS_WORD, FileExportFormat.OPEN_DOCUMENT_TEXT => FileTypes.ODT, @@ -167,8 +173,8 @@ public static class FileExportFormatExtensions /// turns every umlaut into garbage. Text files get none: editors, compilers, and LaTeX have /// no use for it and some of them stumble over it. /// - /// The encoding to write the file with. - public Encoding ToFileEncoding() => format switch + /// The encoding to write the file with. + public Encoding FileEncoding => format switch { FileExportFormat.CSV or FileExportFormat.TSV => WITH_BYTE_ORDER_MARK, @@ -221,8 +227,8 @@ public static class FileExportFormatExtensions /// which page it was stays in the title of the source. Verified on 2026-09-15 with LibreOffice /// on an exported .odt. A format added later keeps the page unless it is known to stumble too. /// - /// True, when a reader of this format follows such a link. - public bool FollowsPageAnchors() => format switch + /// True, when a reader of this format follows such a link. + public bool FollowsPageAnchors => format switch { FileExportFormat.MICROSOFT_WORD or FileExportFormat.OPEN_DOCUMENT_TEXT => false, @@ -238,14 +244,14 @@ public static class FileExportFormatExtensions /// no such title, and handed one anyway, they keep it as a document property nobody asked for; /// verified with Pandoc 3.8.3 on 2026-09-23. LaTeX ignores it. /// - /// True, when a document of this format needs a title besides its content. - public bool NeedsPageTitle() => format is FileExportFormat.HTML; + /// True, when a document of this format needs a title besides its content. + public bool NeedsPageTitle => format is FileExportFormat.HTML; /// /// Returns the name Pandoc knows the format by. /// - /// The Pandoc output format, or an empty string when AI Studio writes the file itself. - public string ToPandocOutputFormat() => format switch + /// The Pandoc output format, or an empty string when AI Studio writes the file itself. + public string PandocOutputFormat => format switch { FileExportFormat.MICROSOFT_WORD => "docx", FileExportFormat.OPEN_DOCUMENT_TEXT => "odt", @@ -258,39 +264,39 @@ public static class FileExportFormatExtensions /// /// Determines whether writing the format needs Pandoc. /// - /// True, when Pandoc converts the message; false, when AI Studio writes the file itself. - public bool UsesPandoc() => !string.IsNullOrWhiteSpace(format.ToPandocOutputFormat()); - } + /// True, when Pandoc converts the message; false, when AI Studio writes the file itself. + public bool UsesPandoc => !string.IsNullOrWhiteSpace(format.PandocOutputFormat); - /// - /// Reads which format a model means when it names a language behind the opening fence of a - /// code block. - /// - /// - /// A model which answers with a finished file puts it into a code block and names its language, - /// as in ```html. Models do not agree on the spelling, so we accept the usual names of a format - /// in any case. Only formats which are plain text appear here: a code block holds text, never - /// a Word document. A block in any other language, or in none, is code, see - /// SourceCodeLanguages.FromCodeFenceLanguage. - /// - /// The language behind the opening fence, as Markdig reads it into - /// FencedCodeBlock.Info. - /// The format the language names, or NONE when it names none of ours. - /// True, when the language names a format AI Studio writes. - public static bool TryFromCodeFenceLanguage(string? language, out FileExportFormat format) - { - format = language?.Trim().ToLowerInvariant() switch + /// + /// Reads which format a model means when it names a language behind the opening fence of a + /// code block. + /// + /// + /// A model which answers with a finished file puts it into a code block and names its language, + /// as in ```html. Models do not agree on the spelling, so we accept the usual names of a format + /// in any case. Only formats which are plain text appear here: a code block holds text, never + /// a Word document. A block in any other language, or in none, is code, see + /// SourceCodeLanguages.FromCodeFenceLanguage. + /// + /// The language behind the opening fence, as Markdig reads it into + /// FencedCodeBlock.Info. + /// The format the language names, or NONE when it names none of ours. + /// True, when the language names a format AI Studio writes. + public static bool TryFromCodeFenceLanguage(string? language, out FileExportFormat namedFormat) { - "html" => FileExportFormat.HTML, - "latex" or "tex" => FileExportFormat.LATEX, - "markdown" or "md" => FileExportFormat.MARKDOWN, - "csv" => FileExportFormat.CSV, - "tsv" => FileExportFormat.TSV, + namedFormat = language?.Trim().ToLowerInvariant() switch + { + "html" => FileExportFormat.HTML, + "latex" or "tex" => FileExportFormat.LATEX, + "markdown" or "md" => FileExportFormat.MARKDOWN, + "csv" => FileExportFormat.CSV, + "tsv" => FileExportFormat.TSV, - _ => FileExportFormat.NONE, - }; + _ => FileExportFormat.NONE, + }; - return format is not FileExportFormat.NONE; + return namedFormat is not FileExportFormat.NONE; + } } /// diff --git a/app/MindWork AI Studio/Tools/FileExtractionErrorCodeExtensions.cs b/app/MindWork AI Studio/Tools/FileExtractionErrorCodeExtensions.cs index e215fb01d..948c3026a 100644 --- a/app/MindWork AI Studio/Tools/FileExtractionErrorCodeExtensions.cs +++ b/app/MindWork AI Studio/Tools/FileExtractionErrorCodeExtensions.cs @@ -22,8 +22,8 @@ internal static class FileExtractionErrorCodeExtensions /// Gets a value indicating whether reading the file again will fail again, as long as the file /// itself does not change. /// - /// True, when the reason lies in the file itself. - internal bool IsPermanentIndexingFailure() => code switch + /// True, when the reason lies in the file itself. + internal bool IsPermanentIndexingFailure => code switch { // // The reason lies in the file. Reading it again without changing it produces the same @@ -60,8 +60,8 @@ internal static class FileExtractionErrorCodeExtensions /// Used to group the files of an indexing run by what happened to them: nine hundred entries /// which all say the same sentence are one cause, not nine hundred. /// - /// The localized name of the cause, or an empty text when the code has none. - internal string GetIndexingCauseName() => code switch + /// The localized name of the cause, or an empty text when the code has none. + internal string IndexingCauseName => code switch { FileExtractionErrorCode.NO_TEXT_EXTRACTED => TB("No readable text"), FileExtractionErrorCode.NO_CONTENT => TB("No content"), diff --git a/app/MindWork AI Studio/Tools/Mail/MailboxConnectionFailureExtensions.cs b/app/MindWork AI Studio/Tools/Mail/MailboxConnectionFailureExtensions.cs index acb19f578..db2576998 100644 --- a/app/MindWork AI Studio/Tools/Mail/MailboxConnectionFailureExtensions.cs +++ b/app/MindWork AI Studio/Tools/Mail/MailboxConnectionFailureExtensions.cs @@ -11,7 +11,7 @@ public static class MailboxConnectionFailureExtensions /// /// What went wrong, and what the user can do about it. /// - public string GetDescription() => failure switch + public string Description => failure switch { MailboxConnectionFailure.AUTHENTICATION_FAILED => TB("The server rejected the username or the password. Some providers require an app password instead of your usual password."), MailboxConnectionFailure.NETWORK_UNAVAILABLE => TB("The server could not be reached. Please check the host and the port, and whether you need a VPN connection."), diff --git a/app/MindWork AI Studio/Tools/Mail/MailboxProviderTemplateExtensions.cs b/app/MindWork AI Studio/Tools/Mail/MailboxProviderTemplateExtensions.cs index 423c62cbf..81aacaf23 100644 --- a/app/MindWork AI Studio/Tools/Mail/MailboxProviderTemplateExtensions.cs +++ b/app/MindWork AI Studio/Tools/Mail/MailboxProviderTemplateExtensions.cs @@ -11,7 +11,7 @@ public static class MailboxProviderTemplateExtensions /// /// What the user enters as the username at this provider. /// - public string GetDescription() => format switch + public string Description => format switch { MailboxUsernameFormat.EMAIL_ADDRESS => TB("Your full e-mail address."), MailboxUsernameFormat.ADDRESS_NAME_PART => TB("The part of your e-mail address before the @ sign. When that does not work, try your full e-mail address."), diff --git a/app/MindWork AI Studio/Tools/Media/MediaImportOwnerKindExtensions.cs b/app/MindWork AI Studio/Tools/Media/MediaImportOwnerKindExtensions.cs index 84af128ee..f194417bf 100644 --- a/app/MindWork AI Studio/Tools/Media/MediaImportOwnerKindExtensions.cs +++ b/app/MindWork AI Studio/Tools/Media/MediaImportOwnerKindExtensions.cs @@ -16,7 +16,7 @@ public static class MediaImportOwnerKindExtensions /// the file, nor deliver the completed transcripts back into its own list afterwards, because /// the owner already holds them. All other owners rely on that delivery instead. /// - /// true when the owner persists its own sources. - public bool PersistsOwnSources() => kind is MediaImportOwnerKind.VISUAL_BRIEFING; + /// true when the owner persists its own sources. + public bool PersistsOwnSources => kind is MediaImportOwnerKind.VISUAL_BRIEFING; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/MessageFile.cs b/app/MindWork AI Studio/Tools/MessageFile.cs index 32c94c321..a25570f12 100644 --- a/app/MindWork AI Studio/Tools/MessageFile.cs +++ b/app/MindWork AI Studio/Tools/MessageFile.cs @@ -32,24 +32,24 @@ public sealed record MessageFile(int Ordinal, int Position, string Caption, File /// Returns the name of the file's type as shown to the user, for example "Webpage (.html)" or /// "Python (.py)". /// - public string ToName() => this.IsSourceCode ? this.Language.ToName() : this.Format.ToName(); + public string ToName() => this.IsSourceCode ? this.Language.ToName() : this.Format.Name; /// /// Returns the icon of the file's type. /// - public string ToIcon() => this.Format.ToIcon(); + public string ToIcon() => this.Format.Icon; /// /// Returns what tells a file of this type apart: its extension, for example ".html", or the /// fixed name a tool looks for, such as Dockerfile. /// - public string ToFileExtensionOrName() => this.IsSourceCode ? this.Language.ToFileExtensionOrName() : this.Format.ToFileExtension(); + public string ToFileExtensionOrName() => this.IsSourceCode ? this.Language.ToFileExtensionOrName() : this.Format.FileExtension; /// /// Returns the filter which the save dialog offers for the file. /// /// The filter, or null when AI Studio cannot write the file itself. - public FileTypeFilter? ToFileTypeFilter() => this.IsSourceCode ? this.Language.ToFileTypeFilter() : this.Format.ToFileTypeFilter(); + public FileTypeFilter? ToFileTypeFilter() => this.IsSourceCode ? this.Language.ToFileTypeFilter() : this.Format.FileTypeFilter; /// /// Returns the file name the save dialog starts with. @@ -61,5 +61,5 @@ public sealed record MessageFile(int Ordinal, int Position, string Caption, File /// /// Returns the encoding the file gets written with. /// - public Encoding ToFileEncoding() => this.IsSourceCode ? this.Language.ToFileEncoding() : this.Format.ToFileEncoding(); + public Encoding ToFileEncoding() => this.IsSourceCode ? this.Language.ToFileEncoding() : this.Format.FileEncoding; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/MudThemeExtensions.cs b/app/MindWork AI Studio/Tools/MudThemeExtensions.cs index 43d964470..9c44f5753 100644 --- a/app/MindWork AI Studio/Tools/MudThemeExtensions.cs +++ b/app/MindWork AI Studio/Tools/MudThemeExtensions.cs @@ -14,12 +14,12 @@ public static class MudThemeExtensions public string GetActivityIndicatorColor(SettingsManager settingsManager) => settingsManager.IsDarkMode switch { - true => theme.GetActivityIndicatorDarkColor(), - false => theme.GetActivityIndicatorLightColor(), + true => theme.ActivityIndicatorDarkColor, + false => theme.ActivityIndicatorLightColor, }; - public string GetActivityIndicatorLightColor() => theme.PaletteLight.Info.Value; + public string ActivityIndicatorLightColor => theme.PaletteLight.Info.Value; - public string GetActivityIndicatorDarkColor() => theme.PaletteDark.InfoLighten; + public string ActivityIndicatorDarkColor => theme.PaletteDark.InfoLighten; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/Pandoc.cs b/app/MindWork AI Studio/Tools/Pandoc.cs index 366d9a58d..f060c37ff 100644 --- a/app/MindWork AI Studio/Tools/Pandoc.cs +++ b/app/MindWork AI Studio/Tools/Pandoc.cs @@ -14,7 +14,7 @@ public static partial class Pandoc private static string TB(string fallbackEN) => PluginSystem.I18N.I.T(fallbackEN, typeof(Pandoc).Namespace, nameof(Pandoc)); // Pandoc is a program of its own, so it has to fit the machine, not the build of AI Studio: - private static readonly RID CPU_ARCHITECTURE = RIDExtensions.GetCurrentRID(); + private static readonly RID CPU_ARCHITECTURE = RID.Current; private const string DOWNLOAD_URL = "https://github.com/jgm/pandoc/releases/download"; private const string LATEST_URL = "https://github.com/jgm/pandoc/releases/latest"; @@ -173,7 +173,7 @@ public static partial class Pandoc if (string.IsNullOrWhiteSpace(uri)) { await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Error, TB("AI Studio couldn't install Pandoc because the archive type is unknown."))); - LOG.LogError("Pandoc was not installed, no archive is available for architecture '{Architecture}'.", CPU_ARCHITECTURE.ToUserFriendlyName()); + LOG.LogError("Pandoc was not installed, no archive is available for architecture '{Architecture}'.", CPU_ARCHITECTURE.UserFriendlyName); return; } @@ -477,7 +477,7 @@ public static partial class Pandoc return $"{baseUri}arm64-macOS.pkg"; default: - await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Terminal, string.Format(TB("Installers are not available on {0} systems."), CPU_ARCHITECTURE.ToUserFriendlyName()))); + await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Terminal, string.Format(TB("Installers are not available on {0} systems."), CPU_ARCHITECTURE.UserFriendlyName))); return string.Empty; } } diff --git a/app/MindWork AI Studio/Tools/PandocExport.cs b/app/MindWork AI Studio/Tools/PandocExport.cs index d67dd2df6..103ea3c5f 100644 --- a/app/MindWork AI Studio/Tools/PandocExport.cs +++ b/app/MindWork AI Studio/Tools/PandocExport.cs @@ -31,7 +31,7 @@ public static class PandocExport /// True, when the document was written. public static async Task ConvertAsync(RustService rustService, string markdownText, string targetFilePath, FileExportFormat format, CancellationToken token = default) { - if (!format.UsesPandoc()) + if (!format.UsesPandoc) throw new ArgumentOutOfRangeException(nameof(format), format, "Pandoc cannot write this format."); var tempMarkdownFilePath = string.Empty; @@ -49,7 +49,7 @@ public static class PandocExport .Create() .UseStandaloneMode() .WithInputFormat("gfm+emoji+tex_math_dollars") - .WithOutputFormat(format.ToPandocOutputFormat()) + .WithOutputFormat(format.PandocOutputFormat) .WithOutputFile(targetFilePath) .WithInputFile(tempMarkdownFilePath); @@ -58,7 +58,7 @@ public static class PandocExport // reaches the page as a string which Pandoc escapes; only a file named true or false // is read as a switch and keeps the temporary name. // - if (format.NeedsPageTitle()) + if (format.NeedsPageTitle) pandocBuilder.AddArgument("-M").AddArgument($"pagetitle={Path.GetFileNameWithoutExtension(targetFilePath)}"); var pandoc = await pandocBuilder.BuildAsync(rustService); @@ -127,14 +127,14 @@ public static class PandocExport /// True, when the document was written. public static async Task ToDocument(RustService rustService, PandocAvailabilityService pandocAvailability, AIGeneratedContentDisclosureService? disclosureService, string dialogTitle, FileExportFormat format, IContent markdownContent, string? fileName = null) { - if (!format.UsesPandoc() || format.ToFileTypeFilter() is not { } fileTypeFilter) + if (!format.UsesPandoc || format.FileTypeFilter is not { } fileTypeFilter) throw new ArgumentOutOfRangeException(nameof(format), format, "Pandoc cannot write this format."); // // We read the text before we ask for a path: when there is nothing to convert, the user // should learn that right away instead of picking a file first and getting an error afterwards. // - if (!markdownContent.TryGetExportMarkdown(out var markdownText, format.FollowsPageAnchors())) + if (!markdownContent.TryGetExportMarkdown(out var markdownText, format.FollowsPageAnchors)) { LOGGER.LogWarning("Cannot export the content as {ExportFormat}, because it carries no text.", format); await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Cancel, TB("Only text messages can be exported."))); diff --git a/app/MindWork AI Studio/Tools/PandocProcessBuilder.cs b/app/MindWork AI Studio/Tools/PandocProcessBuilder.cs index 87d1b27f4..6cfc457da 100644 --- a/app/MindWork AI Studio/Tools/PandocProcessBuilder.cs +++ b/app/MindWork AI Studio/Tools/PandocProcessBuilder.cs @@ -10,7 +10,7 @@ namespace AIStudio.Tools; public sealed class PandocProcessBuilder { // Pandoc is a program of its own, so it has to fit the machine, not the build of AI Studio: - private static readonly RID CPU_ARCHITECTURE = RIDExtensions.GetCurrentRID(); + private static readonly RID CPU_ARCHITECTURE = RID.Current; private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger(nameof(PandocProcessBuilder)); private const string FLATPAK_PANDOC_PLUGIN_BIN_DIRECTORY = "/app/plugins/pandoc/bin"; diff --git a/app/MindWork AI Studio/Tools/PlainFileExport.cs b/app/MindWork AI Studio/Tools/PlainFileExport.cs index 45e3baa1d..aba0f1bdb 100644 --- a/app/MindWork AI Studio/Tools/PlainFileExport.cs +++ b/app/MindWork AI Studio/Tools/PlainFileExport.cs @@ -89,7 +89,7 @@ public static class PlainFileExport .Where(entry => entry.File is not null) .OrderBy(entry => entry.Position) .Select(entry => new MessageFile( - entry.File!.Format.IsTabular() ? ++numberOfTables : ++numberOfCodeBlocks, + entry.File!.Format.IsTabular ? ++numberOfTables : ++numberOfCodeBlocks, entry.Position, Caption: HeadingAbove(entry.Position) is { Length: > 0 } heading ? heading : entry.File!.Fallback, entry.File!.Format, @@ -153,10 +153,10 @@ public static class PlainFileExport var content = block.Lines.ToString(); var language = CodeLanguageDetector.FenceLanguageOf(block.Info, content); - if (!FileExportFormatExtensions.TryFromCodeFenceLanguage(language, out var format)) + if (!FileExportFormat.TryFromCodeFenceLanguage(language, out var format)) return new(string.Empty, FileExportFormat.SOURCE_CODE, SourceCodeLanguages.FromCodeFenceLanguage(language), content); - if (!format.IsTabular()) + if (!format.IsTabular) return new(string.Empty, format, SourceCodeLanguage.NONE, content); var blockSeparator = format is FileExportFormat.TSV ? '\t' : ','; @@ -239,10 +239,10 @@ public static class PlainFileExport /// True, when the file was written. public static async Task ToFile(RustService rustService, string dialogTitle, FileExportFormat format, string fileContent, string? fileName = null) { - if (!format.IsPlainText() || format.ToFileTypeFilter() is not { } fileTypeFilter) + if (!format.IsPlainText || format.FileTypeFilter is not { } fileTypeFilter) throw new ArgumentOutOfRangeException(nameof(format), format, "AI Studio cannot write this format itself."); - return await WriteFile(rustService, dialogTitle, format, fileTypeFilter, format.ToSuggestedFileName(fileName), format.ToFileEncoding(), fileContent); + return await WriteFile(rustService, dialogTitle, format, fileTypeFilter, format.ToSuggestedFileName(fileName), format.FileEncoding, fileContent); } /// @@ -262,7 +262,7 @@ public static class PlainFileExport /// True, when the file was written. public static async Task ToFile(RustService rustService, string dialogTitle, MessageFile file, string fileContent, string? fileName = null) { - if (!file.Format.IsPlainText() || file.ToFileTypeFilter() is not { } fileTypeFilter) + if (!file.Format.IsPlainText || file.ToFileTypeFilter() is not { } fileTypeFilter) throw new ArgumentOutOfRangeException(nameof(file), file.Format, "AI Studio cannot write this format itself."); return await WriteFile(rustService, dialogTitle, file.Format, fileTypeFilter, file.ToSuggestedFileName(fileName), file.ToFileEncoding(), fileContent); diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantPluginAuditService.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantPluginAuditService.cs index 3c2a2c297..9a82b1814 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantPluginAuditService.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantPluginAuditService.cs @@ -25,7 +25,7 @@ public sealed class AssistantPluginAuditService(AssistantAuditAgent auditAgent) AuditProviderName = provider == Settings.Provider.NONE ? string.Empty : provider.InstanceName, - Level = AssistantAuditLevelExtensions.Parse(result.Level), + Level = AssistantAuditLevel.ParseOrUnknown(result.Level), Summary = result.Summary, Confidence = result.Confidence, PromptPreview = promptPreview, diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentTypeExtensions.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentTypeExtensions.cs index 58fe09d35..27b884d2f 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentTypeExtensions.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentTypeExtensions.cs @@ -6,7 +6,7 @@ public static class AssistantComponentTypeExtensions extension(AssistantComponentType type) { - public string GetDisplayName() => type switch + public string DisplayName => type switch { AssistantComponentType.FORM => TB("Root"), AssistantComponentType.TEXT_AREA => TB("Text Area"), @@ -36,7 +36,7 @@ public static class AssistantComponentTypeExtensions _ => TB("Unknown Element") }; - public string GetIcon() => type switch + public string Icon => type switch { AssistantComponentType.BUTTON => MudBlazor.Icons.Material.Filled.AdsClick, AssistantComponentType.BUTTON_GROUP => MudBlazor.Icons.Material.Filled.LinearScale, diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/PluginAssistantSecurityResolver.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/PluginAssistantSecurityResolver.cs index 28a4c163a..6e23fc7e8 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/PluginAssistantSecurityResolver.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/PluginAssistantSecurityResolver.cs @@ -105,8 +105,8 @@ public static class PluginAssistantSecurityResolver CanActivatePlugin = true, CanStartAssistant = true, AuditLabel = TB("Safe"), - AuditColor = AssistantAuditLevel.SAFE.GetColor(), - AuditIcon = AssistantAuditLevel.SAFE.GetIcon(), + AuditColor = AssistantAuditLevel.SAFE.Color, + AuditIcon = AssistantAuditLevel.SAFE.Icon, AvailabilityLabel = GetAvailabilityLabel(requiresAudit: false, hasAudit: true, hasHashMismatch: false, isBlocked: false, canOverride: false), AvailabilityColor = GetAvailabilityColor(requiresAudit: false, hasAudit: true, hasHashMismatch: false, isBlocked: false, canOverride: false), AvailabilityIcon = GetAvailabilityIcon(requiresAudit: false, hasAudit: true, hasHashMismatch: false, isBlocked: false, canOverride: false), @@ -153,8 +153,8 @@ public static class PluginAssistantSecurityResolver CanActivatePlugin = !isBlocked, CanStartAssistant = !isBlocked, AuditLabel = TB("Unknown"), - AuditColor = AssistantAuditLevel.UNKNOWN.GetColor(), - AuditIcon = AssistantAuditLevel.UNKNOWN.GetIcon(), + AuditColor = AssistantAuditLevel.UNKNOWN.Color, + AuditIcon = AssistantAuditLevel.UNKNOWN.Icon, AvailabilityLabel = GetAvailabilityLabel(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false), AvailabilityColor = GetAvailabilityColor(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false), AvailabilityIcon = GetAvailabilityIcon(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false), @@ -192,8 +192,8 @@ public static class PluginAssistantSecurityResolver CanActivatePlugin = !isBlocked, CanStartAssistant = !isBlocked, AuditLabel = TB("Unknown"), - AuditColor = AssistantAuditLevel.UNKNOWN.GetColor(), - AuditIcon = AssistantAuditLevel.UNKNOWN.GetIcon(), + AuditColor = AssistantAuditLevel.UNKNOWN.Color, + AuditIcon = AssistantAuditLevel.UNKNOWN.Icon, AvailabilityLabel = GetAvailabilityLabel(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false), AvailabilityColor = GetAvailabilityColor(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false), AvailabilityIcon = GetAvailabilityIcon(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false), @@ -233,15 +233,15 @@ public static class PluginAssistantSecurityResolver CanOverride = !isBlockedByMinimum, CanActivatePlugin = !isBlockedByMinimum, CanStartAssistant = !isBlockedByMinimum, - AuditLabel = auditLevel.GetName(), - AuditColor = auditLevel.GetColor(), - AuditIcon = auditLevel.GetIcon(), + AuditLabel = auditLevel.Name, + AuditColor = auditLevel.Color, + AuditIcon = auditLevel.Icon, AvailabilityLabel = GetAvailabilityLabel(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride), AvailabilityColor = GetAvailabilityColor(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride), AvailabilityIcon = GetAvailabilityIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride), StatusLabel = GetAvailabilityLabel(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride), SourceLabel = TB("User Audit"), - SourceColor = auditLevel.GetColor(), + SourceColor = auditLevel.Color, SourceIcon = MudBlazor.Icons.Material.Filled.Verified, BadgeIcon = GetSecurityBadgeIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride), Headline = isBlockedByMinimum @@ -250,10 +250,10 @@ public static class PluginAssistantSecurityResolver ? TB("This assistant can still be used because audit enforcement is disabled.") : TB("This assistant can still be used because your settings allow it."), Description = isBlockedByMinimum - ? string.Format(TB("The current audit result '{0}' is below your required minimum level '{1}'. Your security settings therefore block this assistant plugin."), auditLevel.GetName(), auditSettings.MinimumLevel.GetName()) + ? string.Format(TB("The current audit result '{0}' is below your required minimum level '{1}'. Your security settings therefore block this assistant plugin."), auditLevel.Name, auditSettings.MinimumLevel.Name) : isEnforcementDisabled - ? string.Format(TB("The current audit result is '{0}', which is below your required minimum level '{1}'. Audit enforcement is currently disabled, so this assistant plugin can still be enabled or used."), auditLevel.GetName(), auditSettings.MinimumLevel.GetName()) - : string.Format(TB("The current audit result is '{0}', which is below your required minimum level '{1}'. Your settings still allow manual activation, but the assistant keeps this security status and should be reviewed carefully."), auditLevel.GetName(), auditSettings.MinimumLevel.GetName()), + ? string.Format(TB("The current audit result is '{0}', which is below your required minimum level '{1}'. Audit enforcement is currently disabled, so this assistant plugin can still be enabled or used."), auditLevel.Name, auditSettings.MinimumLevel.Name) + : string.Format(TB("The current audit result is '{0}', which is below your required minimum level '{1}'. Your settings still allow manual activation, but the assistant keeps this security status and should be reviewed carefully."), auditLevel.Name, auditSettings.MinimumLevel.Name), StatusColor = GetAvailabilityColor(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride), StatusIcon = GetAvailabilityIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride), ActionLabel = TB("Open Security Check"), @@ -278,19 +278,19 @@ public static class PluginAssistantSecurityResolver CanOverride = false, CanActivatePlugin = canUsePlugin, CanStartAssistant = canUsePlugin, - AuditLabel = auditLevelDefault.GetName(), - AuditColor = auditLevelDefault.GetColor(), - AuditIcon = auditLevelDefault.GetIcon(), + AuditLabel = auditLevelDefault.Name, + AuditColor = auditLevelDefault.Color, + AuditIcon = auditLevelDefault.Icon, AvailabilityLabel = GetAvailabilityLabel(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false), AvailabilityColor = GetAvailabilityColor(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false), AvailabilityIcon = GetAvailabilityIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false), StatusLabel = GetAvailabilityLabel(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false), SourceLabel = TB("User Audit"), - SourceColor = auditLevelDefault.GetColor(), + SourceColor = auditLevelDefault.Color, SourceIcon = MudBlazor.Icons.Material.Filled.Verified, BadgeIcon = GetSecurityBadgeIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false), Headline = TB("This assistant is currently unlocked."), - Description = string.Format(TB("The stored audit matches the current plugin code and meets your required minimum level '{0}'."), auditSettings.MinimumLevel.GetName()), + Description = string.Format(TB("The stored audit matches the current plugin code and meets your required minimum level '{0}'."), auditSettings.MinimumLevel.Name), StatusColor = GetAvailabilityColor(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false), StatusIcon = GetAvailabilityIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false), ActionLabel = TB("Open Security Check"), diff --git a/app/MindWork AI Studio/Tools/PluginSystem/ConfigurationSnippetImport.cs b/app/MindWork AI Studio/Tools/PluginSystem/ConfigurationSnippetImport.cs index 5de7e931b..ffaa6a26d 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/ConfigurationSnippetImport.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/ConfigurationSnippetImport.cs @@ -306,6 +306,6 @@ public static class ConfigurationSnippetImport return TB("The token or password of the data source cannot be decrypted on this computer. Such data sources can only be imported where the encryption secret of your organization is configured."); } - return string.Format(TB("The pasted configuration is not a valid configuration of the type '{0}'."), type.GetName()); + return string.Format(TB("The pasted configuration is not a valid configuration of the type '{0}'."), type.Name); } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/PluginSystem/ConfigurationSnippetParser.cs b/app/MindWork AI Studio/Tools/PluginSystem/ConfigurationSnippetParser.cs index afa9ec1e5..cbd9a17c5 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/ConfigurationSnippetParser.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/ConfigurationSnippetParser.cs @@ -51,8 +51,8 @@ public sealed class ConfigurationSnippetParser var section = parser.ReadBracketedString(); if (section != expectedSection) throw new FormatException(PluginConfigurationObjectDescriptors.TryGet(section, out var otherDescriptor) - ? string.Format(TB("The pasted configuration describes the type '{0}', but only the type '{1}' can be imported here."), otherDescriptor.Type.GetName(), type.GetName()) - : string.Format(TB("The pasted configuration does not describe the type '{0}', which can be imported here."), type.GetName())); + ? string.Format(TB("The pasted configuration describes the type '{0}', but only the type '{1}' can be imported here."), otherDescriptor.Type.Name, type.Name) + : string.Format(TB("The pasted configuration does not describe the type '{0}', which can be imported here."), type.Name)); parser.Expect('['); parser.Expect('#'); diff --git a/app/MindWork AI Studio/Tools/PluginSystem/InternalPluginData.cs b/app/MindWork AI Studio/Tools/PluginSystem/InternalPluginData.cs index d7595f2a0..d4df41e8d 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/InternalPluginData.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/InternalPluginData.cs @@ -2,7 +2,7 @@ namespace AIStudio.Tools.PluginSystem; public readonly record struct InternalPluginData(PluginType Type, Guid Id, string ShortName) { - public string ResourcePath => $"{this.Type.GetDirectory()}/{this.ShortName.ToLowerInvariant()}-{this.Id}"; + public string ResourcePath => $"{this.Type.Directory}/{this.ShortName.ToLowerInvariant()}-{this.Id}"; public string ResourceName => $"{this.ShortName.ToLowerInvariant()}-{this.Id}"; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginCategoryExtensions.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginCategoryExtensions.cs index 755c73b34..86abe16e3 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginCategoryExtensions.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginCategoryExtensions.cs @@ -6,7 +6,7 @@ public static class PluginCategoryExtensions extension(PluginCategory type) { - public string GetName() => type switch + public string Name => type switch { PluginCategory.NONE => TB("None"), PluginCategory.CORE => TB("AI Studio Core"), diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs index 184349342..b298f0e97 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs @@ -489,7 +489,7 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT var resultFileFormatIsValid = ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.ResultFileFormat, this.Id, settingsTable, dryRun, validator: DataBatchProcessing.IsValidResultFileFormat); if (!resultFileFormatIsValid && settingsTable.TryGetValue("DataBatchProcessing.ResultFileFormat", out _)) - LOG.LogWarning("The Batch Processing result file format configured by plugin {ConfigPluginId} must be one of {ResultFileFormats}.", this.Id, string.Join(", ", FileExportFormatExtensions.ANSWER_FORMATS)); + LOG.LogWarning("The Batch Processing result file format configured by plugin {ConfigPluginId} must be one of {ResultFileFormats}.", this.Id, string.Join(", ", FileExportFormat.AnswerFormats)); ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.CsvFileName, this.Id, settingsTable, dryRun); ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.ResultColumnHeader, this.Id, settingsTable, dryRun); diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs index d481e5910..e6e3fee46 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs @@ -58,13 +58,13 @@ public sealed record PluginConfigurationObject private static string DescribeEndpoint(IConfigurationObject configObject) => configObject switch { Settings.Provider { IsSelfHosted: true } provider => provider.Hostname, - Settings.Provider provider => Provider.LLMProvidersExtensions.ToName(provider.UsedLLMProvider), + Settings.Provider provider => Provider.LLMProvidersExtensions.ToName(provider.UsedLLMProvider, translate: true), EmbeddingProvider { IsSelfHosted: true } embeddingProvider => embeddingProvider.Hostname, - EmbeddingProvider embeddingProvider => Provider.LLMProvidersExtensions.ToName(embeddingProvider.UsedLLMProvider), + EmbeddingProvider embeddingProvider => Provider.LLMProvidersExtensions.ToName(embeddingProvider.UsedLLMProvider, translate: true), TranscriptionProvider { IsSelfHosted: true } transcriptionProvider => transcriptionProvider.Hostname, - TranscriptionProvider transcriptionProvider => Provider.LLMProvidersExtensions.ToName(transcriptionProvider.UsedLLMProvider), + TranscriptionProvider transcriptionProvider => Provider.LLMProvidersExtensions.ToName(transcriptionProvider.UsedLLMProvider, translate: true), DataSourceERI_V1 dataSource => dataSource.Hostname, diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObjectTypeExtensions.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObjectTypeExtensions.cs index 8804e72fb..a19443b07 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObjectTypeExtensions.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObjectTypeExtensions.cs @@ -9,7 +9,7 @@ public static class PluginConfigurationObjectTypeExtensions /// /// The name of a type of configuration object, as users read it, e.g., in a message. /// - public string GetName() => type switch + public string Name => type switch { PluginConfigurationObjectType.LLM_PROVIDER => TB("LLM Provider"), PluginConfigurationObjectType.EMBEDDING_PROVIDER => TB("Embedding Provider"), diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Internal.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Internal.cs index b2cbe5156..d9b98334d 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Internal.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Internal.cs @@ -87,7 +87,7 @@ public static partial class PluginFactory { await using var inputStream = resourceFilePath.CreateReadStream(); - var pluginTypeBasePath = Path.Join(INTERNAL_PLUGINS_ROOT, metaData.Type.GetDirectory()); + var pluginTypeBasePath = Path.Join(INTERNAL_PLUGINS_ROOT, metaData.Type.Directory); if (!Directory.Exists(INTERNAL_PLUGINS_ROOT)) Directory.CreateDirectory(INTERNAL_PLUGINS_ROOT); diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginTargetGroupExtensions.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginTargetGroupExtensions.cs index 5dfad0da0..2f8878561 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginTargetGroupExtensions.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginTargetGroupExtensions.cs @@ -6,7 +6,7 @@ public static class PluginTargetGroupExtensions extension(PluginTargetGroup group) { - public string Name() => group switch + public string Name => group switch { PluginTargetGroup.NONE => TB("No target group"), diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginTypeExtensions.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginTypeExtensions.cs index 15c28a219..c3be9f0ee 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginTypeExtensions.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginTypeExtensions.cs @@ -6,7 +6,7 @@ public static class PluginTypeExtensions extension(PluginType type) { - public string GetName() => type switch + public string Name => type switch { PluginType.LANGUAGE => TB("Language plugin"), PluginType.ASSISTANT => TB("Assistant plugin"), @@ -17,7 +17,7 @@ public static class PluginTypeExtensions _ => TB("Unknown plugin type"), }; - public string GetDirectory() => type switch + public string Directory => type switch { PluginType.LANGUAGE => "languages", PluginType.ASSISTANT => "assistants", diff --git a/app/MindWork AI Studio/Tools/PowerPoint/ChosenLayouts.cs b/app/MindWork AI Studio/Tools/PowerPoint/ChosenLayouts.cs index 290c3f2a6..ad3caf6a2 100644 --- a/app/MindWork AI Studio/Tools/PowerPoint/ChosenLayouts.cs +++ b/app/MindWork AI Studio/Tools/PowerPoint/ChosenLayouts.cs @@ -46,7 +46,7 @@ internal sealed record ChosenLayouts(IReadOnlyDictionary /// The kinds of slides the presentation has to have, because the user chose a layout for them. /// - public IEnumerable AddedSlides => Enum.GetValues().Where(purpose => purpose.ChoiceAddsSlide() && this.Families.ContainsKey(purpose)); + public IEnumerable AddedSlides => Enum.GetValues().Where(purpose => purpose.ChoiceAddsSlide && this.Families.ContainsKey(purpose)); /// /// Writes the choices as rules for the model, one line per kind of slide, in the order of the kinds. @@ -64,14 +64,14 @@ internal sealed record ChosenLayouts(IReadOnlyDictionary()) if (this.For(purpose) is { } family) - rules.Append('\n').Append(" - ").Append(family.Id).Append(" for ").Append(purpose.PromptDescription()).Append('.'); + rules.Append('\n').Append(" - ").Append(family.Id).Append(" for ").Append(purpose.PromptDescription).Append('.'); var addedSlides = this.AddedSlides.ToList(); if (addedSlides.Count > 0) { rules.Append('\n').Append(" - The presentation has at least one slide of each of these kinds, on its layout:"); foreach (var purpose in addedSlides) - rules.Append('\n').Append(" - ").Append(this.Families[purpose].Id).Append(": ").Append(purpose.PromptDescription()).Append(", ").Append(purpose.PromptPlacement()).Append('.'); + rules.Append('\n').Append(" - ").Append(this.Families[purpose].Id).Append(": ").Append(purpose.PromptDescription).Append(", ").Append(purpose.PromptPlacement).Append('.'); } return rules.ToString(); diff --git a/app/MindWork AI Studio/Tools/PowerPoint/LayoutPurposeAreaExtensions.cs b/app/MindWork AI Studio/Tools/PowerPoint/LayoutPurposeAreaExtensions.cs index 704dc10db..4ae4acd26 100644 --- a/app/MindWork AI Studio/Tools/PowerPoint/LayoutPurposeAreaExtensions.cs +++ b/app/MindWork AI Studio/Tools/PowerPoint/LayoutPurposeAreaExtensions.cs @@ -13,7 +13,7 @@ internal static class LayoutPurposeAreaExtensions /// /// The name of the area, as the forms show it above its kinds of slides. /// - public string Label() => area switch + public string Label => area switch { LayoutPurposeArea.FRAMING => TB("Structure and framing"), LayoutPurposeArea.GENERAL => TB("General content"), diff --git a/app/MindWork AI Studio/Tools/PowerPoint/LayoutPurposeExtensions.cs b/app/MindWork AI Studio/Tools/PowerPoint/LayoutPurposeExtensions.cs index bc58fa642..e73b27535 100644 --- a/app/MindWork AI Studio/Tools/PowerPoint/LayoutPurposeExtensions.cs +++ b/app/MindWork AI Studio/Tools/PowerPoint/LayoutPurposeExtensions.cs @@ -22,23 +22,23 @@ internal static partial class LayoutPurposeExtensions /// /// The area the forms list a kind of slide in. /// - public LayoutPurposeArea Area() => Describe(purpose).Area; + public LayoutPurposeArea Area => Describe(purpose).Area; /// /// The short name of the choice, e.g., "Layout for chapters". /// - public string Label() => Describe(purpose).Label; + public string Label => Describe(purpose).Label; /// /// The question the choice answers, which says which slides it applies to. /// - public string Question() => Describe(purpose).Question; + public string Question => Describe(purpose).Question; /// /// Describes the slides of this kind for the model, so that it knows which of its slides a choice applies to. /// - /// The description, e.g., "timelines, e.g., the course of a project". - public string PromptDescription() => Describe(purpose).PromptDescription; + /// The description, e.g., "timelines, e.g., the course of a project". + public string PromptDescription => Describe(purpose).PromptDescription; /// /// Whether choosing a layout for this kind of slide also puts such a slide into the presentation. @@ -48,13 +48,13 @@ internal static partial class LayoutPurposeExtensions /// presentation has one follows from its content. The slides which frame a presentation are /// different: whoever chooses a layout for the table of contents or the imprint expects them. /// - public bool ChoiceAddsSlide() => purpose.PromptPlacement() is not null; + public bool ChoiceAddsSlide => purpose.PromptPlacement is not null; /// /// Where a slide goes which a choice puts into the presentation, and what it holds, for the model. /// - /// The rule, or null when a choice adds no slide of this kind. - public string? PromptPlacement() => purpose switch + /// The rule, or null when a choice adds no slide of this kind. + public string? PromptPlacement => purpose switch { LayoutPurpose.TABLE_OF_CONTENTS => "right after the title slide", LayoutPurpose.Q_AND_A => "near the end, before the closing slide; where the occasion suits it, e.g., in a lecture or a workshop, also at the end of chapters, then naming the topic of the chapter", @@ -69,9 +69,9 @@ internal static partial class LayoutPurposeExtensions /// /// The help below the choice: its question, and whether a choice adds such a slide. /// - public string Help() => purpose.ChoiceAddsSlide() - ? $"{purpose.Question()} {TB("Choosing a layout also adds such a slide to the presentation.")}" - : purpose.Question(); + public string Help => purpose.ChoiceAddsSlide + ? $"{purpose.Question} {TB("Choosing a layout also adds such a slide to the presentation.")}" + : purpose.Question; } private static LayoutPurposeInfo Describe(LayoutPurpose purpose) => diff --git a/app/MindWork AI Studio/Tools/PowerPoint/PlaceholderRoleExtensions.cs b/app/MindWork AI Studio/Tools/PowerPoint/PlaceholderRoleExtensions.cs index 1e6b75edb..b3477124e 100644 --- a/app/MindWork AI Studio/Tools/PowerPoint/PlaceholderRoleExtensions.cs +++ b/app/MindWork AI Studio/Tools/PowerPoint/PlaceholderRoleExtensions.cs @@ -27,7 +27,7 @@ internal static class PlaceholderRoleExtensions foreach (var candidate in SLOT_ROLES) { - if (!string.Equals(words[0], candidate.CatalogName(), StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(words[0], candidate.CatalogName, StringComparison.OrdinalIgnoreCase)) continue; var number = 1; @@ -51,7 +51,7 @@ internal static class PlaceholderRoleExtensions /// Footer, slide number and date are filled as well, but by the presentation as a whole rather /// than by a single slide, so they are no slots of a layout. /// - public bool IsSlot() => role switch + public bool IsSlot => role switch { PlaceholderRole.TITLE => true, PlaceholderRole.SUBTITLE => true, @@ -70,7 +70,7 @@ internal static class PlaceholderRoleExtensions /// A layout offering nothing but a title and some labels has no room for content. Such layouts are /// samples or blank pages, and they are left out of the catalog. /// - public bool CarriesContent() => role switch + public bool CarriesContent => role switch { PlaceholderRole.SUBTITLE => true, PlaceholderRole.TEXT => true, @@ -83,7 +83,7 @@ internal static class PlaceholderRoleExtensions /// /// How the role is called in the catalog the model reads. /// - public string CatalogName() => role switch + public string CatalogName => role switch { PlaceholderRole.TITLE => "title", PlaceholderRole.SUBTITLE => "subtitle", diff --git a/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Catalog.cs b/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Catalog.cs index 9250cf337..ff733314f 100644 --- a/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Catalog.cs +++ b/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Catalog.cs @@ -185,7 +185,7 @@ internal sealed partial class PresentationTemplate /// The entry, e.g., element 2 (text box, right, middle, overlaps picture 1) "Image source". private string DescribeElement(TemplateSlideElement element, IReadOnlyList slotsOnSlide) { - var details = new List { element.Kind.CatalogName() }; + var details = new List { element.Kind.CatalogName }; if (element.Bounds is { } bounds) { if (bounds.Area >= (double)this.SlideWidth * this.SlideHeight * BACKGROUND_AREA_SHARE) @@ -280,7 +280,7 @@ internal sealed partial class PresentationTemplate private static string NameOf(TemplateSlot slot, IReadOnlyList slots) { var isOnlyOne = slot.Role is (PlaceholderRole.TITLE or PlaceholderRole.SUBTITLE) && slots.Count(other => other.Role == slot.Role) == 1; - return isOnlyOne ? slot.Role.CatalogName() : $"{slot.Role.CatalogName()} {slot.Ordinal}"; + return isOnlyOne ? slot.Role.CatalogName : $"{slot.Role.CatalogName} {slot.Ordinal}"; } private string DescribePlace(SlotBounds bounds) diff --git a/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Families.cs b/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Families.cs index 3a387ebc1..5f5ae5b99 100644 --- a/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Families.cs +++ b/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Families.cs @@ -24,7 +24,7 @@ internal sealed partial class PresentationTemplate /// private static GroupedLayouts GroupIntoFamilies(IReadOnlyList layouts, long slideWidth, long slideHeight) { - var usableLayouts = layouts.Where(layout => layout.Slots.Any(slot => slot.Role.CarriesContent())).ToList(); + var usableLayouts = layouts.Where(layout => layout.Slots.Any(slot => slot.Role.CarriesContent)).ToList(); var byFirstWord = Group(usableLayouts, VariantWord.FIRST, slideWidth, slideHeight); var byLastWord = Group(usableLayouts, VariantWord.LAST, slideWidth, slideHeight); var groups = CountVariants(byLastWord) > CountVariants(byFirstWord) ? byLastWord : byFirstWord; diff --git a/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Reading.cs b/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Reading.cs index 525b16b84..23299eea5 100644 --- a/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Reading.cs +++ b/app/MindWork AI Studio/Tools/PowerPoint/PresentationTemplate.Reading.cs @@ -148,7 +148,7 @@ internal sealed partial class PresentationTemplate continue; var role = RoleOf(placeholder.Type, bounds, slideArea); - if (!role.IsSlot()) + if (!role.IsSlot) continue; // diff --git a/app/MindWork AI Studio/Tools/PowerPoint/SlideDeckSpecValidator.cs b/app/MindWork AI Studio/Tools/PowerPoint/SlideDeckSpecValidator.cs index 0eb615a38..33c32d5aa 100644 --- a/app/MindWork AI Studio/Tools/PowerPoint/SlideDeckSpecValidator.cs +++ b/app/MindWork AI Studio/Tools/PowerPoint/SlideDeckSpecValidator.cs @@ -159,7 +159,7 @@ internal static class SlideDeckSpecValidator { var familyId = chosen.Families[purpose].Id; if (!newSlideFamilyIds.Contains(familyId)) - issues.Add($"The presentation has no slide on layout {familyId} for {purpose.PromptDescription()}. Add one {purpose.PromptPlacement()}."); + issues.Add($"The presentation has no slide on layout {familyId} for {purpose.PromptDescription}. Add one {purpose.PromptPlacement}."); } if (chosen.For(LayoutPurpose.IMPRINT) is { } imprintFamily && newSlideFamilyIds.Contains(imprintFamily.Id) && newSlideFamilyIds[^1] != imprintFamily.Id) @@ -431,12 +431,12 @@ internal static class SlideDeckSpecValidator var slot = SlotOf(slots, role, 1); if (slot is null) { - issues.Add($"Slide {number} has a {role.CatalogName()}, but layout {layoutId} has none. Choose a layout with a {role.CatalogName()}, or leave it empty."); + issues.Add($"Slide {number} has a {role.CatalogName}, but layout {layoutId} has none. Choose a layout with a {role.CatalogName}, or leave it empty."); return; } if (slot.Capacity is { } capacity) - ValidateCapacity([new SlideParagraph(text, 0)], capacity, $"Slide {number}: the {role.CatalogName()}", issues); + ValidateCapacity([new SlideParagraph(text, 0)], capacity, $"Slide {number}: the {role.CatalogName}", issues); } /// @@ -450,7 +450,7 @@ internal static class SlideDeckSpecValidator return true; issues.Add(slotCount == 0 - ? $"Slide {number} has {count} {PluralOf(role, count)}, but layout {layoutId} has no {role.CatalogName()}. Choose a layout which has one." + ? $"Slide {number} has {count} {PluralOf(role, count)}, but layout {layoutId} has no {role.CatalogName}. Choose a layout which has one." : $"Slide {number} has {count} {PluralOf(role, count)}, but layout {layoutId} has only {slotCount}. Merge them, or choose a layout with more."); return false; @@ -517,5 +517,5 @@ internal static class SlideDeckSpecValidator return Math.Max(1, (int)Math.Ceiling(paragraph.Text.Length / (double)width)); } - private static string PluralOf(PlaceholderRole role, int count) => count == 1 ? role.CatalogName() : $"{role.CatalogName()}s"; + private static string PluralOf(PlaceholderRole role, int count) => count == 1 ? role.CatalogName : $"{role.CatalogName}s"; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/PowerPoint/TemplateSlideElementKindExtensions.cs b/app/MindWork AI Studio/Tools/PowerPoint/TemplateSlideElementKindExtensions.cs index 51c0b7ddb..f01fbbd5c 100644 --- a/app/MindWork AI Studio/Tools/PowerPoint/TemplateSlideElementKindExtensions.cs +++ b/app/MindWork AI Studio/Tools/PowerPoint/TemplateSlideElementKindExtensions.cs @@ -7,7 +7,7 @@ internal static class TemplateSlideElementKindExtensions /// /// How the kind is called in the list of template slides the model reads. /// - public string CatalogName() => kind switch + public string CatalogName => kind switch { TemplateSlideElementKind.TEXT_BOX => "text box", TemplateSlideElementKind.SHAPE => "shape", diff --git a/app/MindWork AI Studio/Tools/ProcessStepTextRouter.cs b/app/MindWork AI Studio/Tools/ProcessStepTextRouter.cs index eebaff489..181b2db86 100644 --- a/app/MindWork AI Studio/Tools/ProcessStepTextRouter.cs +++ b/app/MindWork AI Studio/Tools/ProcessStepTextRouter.cs @@ -22,7 +22,7 @@ public static class ProcessStepTextRouter /// The text representation of the process step. public static string GetText(T step) where T : struct, Enum => step switch { - ReadWebContentSteps x => x.GetText(), + ReadWebContentSteps x => x.Text, _ => DeriveName(step) }; diff --git a/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs b/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs index 5f034b75b..f05fb568d 100644 --- a/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs +++ b/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs @@ -175,7 +175,7 @@ public sealed class AISrcSelWithRetCtxVal : IRagProcess chatThread.RequireProviderConfidence(dataSource.ConfidenceLevel); if (previousRequiredProviderConfidence != chatThread.RequiredProviderConfidence) - LOGGER.LogInformation($"The required provider confidence of the chat thread was updated from '{previousRequiredProviderConfidence.GetName()}' to '{chatThread.RequiredProviderConfidence.GetName()}'."); + LOGGER.LogInformation($"The required provider confidence of the chat thread was updated from '{previousRequiredProviderConfidence.Name}' to '{chatThread.RequiredProviderConfidence.Name}'."); } // diff --git a/app/MindWork AI Studio/Tools/RAG/RetrievalContentCategoryExtensions.cs b/app/MindWork AI Studio/Tools/RAG/RetrievalContentCategoryExtensions.cs index 595bd6d41..fc3727257 100644 --- a/app/MindWork AI Studio/Tools/RAG/RetrievalContentCategoryExtensions.cs +++ b/app/MindWork AI Studio/Tools/RAG/RetrievalContentCategoryExtensions.cs @@ -10,8 +10,8 @@ public static class RetrievalContentCategoryExtensions /// /// Converts an ERI content type to a common retrieval content category. /// - /// The corresponding retrieval content category. - public RetrievalContentCategory ToRetrievalContentCategory() => contentType switch + /// The corresponding retrieval content category. + public RetrievalContentCategory RetrievalContentCategory => contentType switch { ContentType.NONE => RetrievalContentCategory.NONE, ContentType.UNKNOWN => RetrievalContentCategory.UNKNOWN, diff --git a/app/MindWork AI Studio/Tools/RAG/SourcePassageExtensions.cs b/app/MindWork AI Studio/Tools/RAG/SourcePassageExtensions.cs index bbebec553..1a94f990b 100644 --- a/app/MindWork AI Studio/Tools/RAG/SourcePassageExtensions.cs +++ b/app/MindWork AI Studio/Tools/RAG/SourcePassageExtensions.cs @@ -13,8 +13,8 @@ public static class SourcePassageExtensions /// /// Whether the passage comes from a transcript, e.g., of an audio or a video file. /// - /// True for a transcript. - public bool IsTranscript() => passage.Type is RetrievalContentType.TEXT_TRANSCRIPT; + /// True for a transcript. + public bool IsTranscript => passage.Type is RetrievalContentType.TEXT_TRANSCRIPT; /// /// What sort of content the passage is, as the provenance store files it. @@ -23,8 +23,8 @@ public static class SourcePassageExtensions /// Told by what the content is rather than by where it came from: a mail is a mail, whether a /// mailbox data source or a tool handed it over. /// - /// The kind of its entry. - public ProvenanceKind GetProvenanceKind() => passage.Type switch + /// The kind of its entry. + public ProvenanceKind ProvenanceKind => passage.Type switch { RetrievalContentType.TEXT_EMAIL => ProvenanceKind.MAIL, RetrievalContentType.TEXT_WEBSITE => ProvenanceKind.WEB_PAGE, @@ -34,8 +34,8 @@ public static class SourcePassageExtensions /// /// Whether the passage holds texts which belong into the provenance store, see SourcePassage.ProvenanceId. /// - /// False once the texts are stored, and for a passage without any, such as an image. - public bool HoldsTextsToStore() => passage.ProvenanceId is null && (passage.Text.Length > 0 || passage.SurroundingContent.Count > 0); + /// False once the texts are stored, and for a passage without any, such as an image. + public bool HoldsTextsToStore => passage.ProvenanceId is null && (passage.Text.Length > 0 || passage.SurroundingContent.Count > 0); /// /// Names where the passage is in its document, e.g., "Page 4", "Pages 4–5", "Budget: rows 3–9", "Lines 40–85", or "Part 3". diff --git a/app/MindWork AI Studio/Tools/SecretStoreTypeExtensions.cs b/app/MindWork AI Studio/Tools/SecretStoreTypeExtensions.cs index 963c25209..79799ae13 100644 --- a/app/MindWork AI Studio/Tools/SecretStoreTypeExtensions.cs +++ b/app/MindWork AI Studio/Tools/SecretStoreTypeExtensions.cs @@ -11,8 +11,8 @@ public static class SecretStoreTypeExtensions /// /// LLM_PROVIDER uses the legacy "provider" prefix for backward compatibility. /// - /// The corresponding prefix string. - public string Prefix() => type switch + /// The corresponding prefix string. + public string Prefix => type switch { SecretStoreType.LLM_PROVIDER => "provider", SecretStoreType.EMBEDDING_PROVIDER => "embedding", diff --git a/app/MindWork AI Studio/Tools/Security/PromptInjectionFindingCategoryExtensions.cs b/app/MindWork AI Studio/Tools/Security/PromptInjectionFindingCategoryExtensions.cs index 73db014ed..1c00339ad 100644 --- a/app/MindWork AI Studio/Tools/Security/PromptInjectionFindingCategoryExtensions.cs +++ b/app/MindWork AI Studio/Tools/Security/PromptInjectionFindingCategoryExtensions.cs @@ -8,7 +8,7 @@ public static class PromptInjectionFindingCategoryExtensions extension(PromptInjectionFindingCategory category) { - public string GetDisplayName() => category switch + public string DisplayName => category switch { PromptInjectionFindingCategory.OVERRIDE => TB("Attempt to override instructions"), PromptInjectionFindingCategory.ROLE_OVERRIDE => TB("Attempt to change the AI's role"), diff --git a/app/MindWork AI Studio/Tools/Security/PromptInjectionSourceKindExtensions.cs b/app/MindWork AI Studio/Tools/Security/PromptInjectionSourceKindExtensions.cs index c46569781..cc3204695 100644 --- a/app/MindWork AI Studio/Tools/Security/PromptInjectionSourceKindExtensions.cs +++ b/app/MindWork AI Studio/Tools/Security/PromptInjectionSourceKindExtensions.cs @@ -8,7 +8,7 @@ public static class PromptInjectionSourceKindExtensions extension(PromptInjectionSourceKind kind) { - public string GetDisplayName() => kind switch + public string DisplayName => kind switch { PromptInjectionSourceKind.WEB_CONTENT => TB("Web content"), PromptInjectionSourceKind.FILE_CONTENT => TB("File content"), diff --git a/app/MindWork AI Studio/Tools/Services/DataSourceEmbeddingService.cs b/app/MindWork AI Studio/Tools/Services/DataSourceEmbeddingService.cs index 1f2ee7605..38fcb0b99 100644 --- a/app/MindWork AI Studio/Tools/Services/DataSourceEmbeddingService.cs +++ b/app/MindWork AI Studio/Tools/Services/DataSourceEmbeddingService.cs @@ -873,17 +873,17 @@ public sealed partial class DataSourceEmbeddingService(SettingsManager settingsM if (!AllowsEmbedding(dataSource, embeddingProvider.GetConfidenceLevel(settingsManager))) { - var errorMessage = dataSource is DataSourceMailbox && !dataSource.ConfidenceLevel.IsAllowedMailboxConfidence() + var errorMessage = dataSource is DataSourceMailbox && !dataSource.ConfidenceLevel.IsAllowedMailboxConfidence ? TB("The mailbox has no valid confidence level, so no provider may read it. Please choose one in the settings of the mailbox.") - : string.Format(TB("The selected embedding provider is not allowed to index this data source. The data source asks for the confidence level '{0}', while the embedding provider has '{1}'."), dataSource.ConfidenceLevel.GetName(), embeddingProvider.GetConfidenceLevel(settingsManager).GetName()); + : string.Format(TB("The selected embedding provider is not allowed to index this data source. The data source asks for the confidence level '{0}', while the embedding provider has '{1}'."), dataSource.ConfidenceLevel.Name, embeddingProvider.GetConfidenceLevel(settingsManager).Name); logger.LogWarning( "Skipping background embeddings for data source '{DataSourceName}' ({DataSourceId}) because embedding provider '{EmbeddingProviderName}' ({EmbeddingProviderId}) does not meet the required confidence. RequiredConfidence={RequiredConfidence}, EmbeddingProviderConfidence={EmbeddingProviderConfidence}.", dataSource.Name, dataSource.Id, embeddingProvider.Name, embeddingProvider.Id, - dataSource.ConfidenceLevel.GetName(), - embeddingProvider.GetConfidenceLevel(settingsManager).GetName()); + dataSource.ConfidenceLevel.Name, + embeddingProvider.GetConfidenceLevel(settingsManager).Name); token.ThrowIfCancellationRequested(); this.UpsertStatus(this.GetFallbackStatus(dataSource, errorMessage)); diff --git a/app/MindWork AI Studio/Tools/Services/DataSourceService.cs b/app/MindWork AI Studio/Tools/Services/DataSourceService.cs index a1184f599..821ee77cc 100644 --- a/app/MindWork AI Studio/Tools/Services/DataSourceService.cs +++ b/app/MindWork AI Studio/Tools/Services/DataSourceService.cs @@ -406,7 +406,7 @@ public sealed class DataSourceService { if (!provider.ConfidenceLevel.AllowsDataSourceConfidenceLevel(internalSource.ConfidenceLevel)) { - this.logger.LogWarning($"The internal data source '{source.Name}' (id={source.Id}) requires provider confidence '{internalSource.ConfidenceLevel.GetName()}'. The {provider.Role} only has confidence '{provider.ConfidenceLevel.GetName()}'. We skip this source."); + this.logger.LogWarning($"The internal data source '{source.Name}' (id={source.Id}) requires provider confidence '{internalSource.ConfidenceLevel.Name}'. The {provider.Role} only has confidence '{provider.ConfidenceLevel.Name}'. We skip this source."); return null; } } @@ -420,7 +420,7 @@ public sealed class DataSourceService var embeddingProviderConfidence = embeddingProvider.GetConfidenceLevel(this.settingsManager); if (!embeddingProviderConfidence.AllowsDataSourceConfidenceLevel(internalSource.ConfidenceLevel)) { - this.logger.LogWarning($"The internal data source '{source.Name}' (id={source.Id}) requires provider confidence '{internalSource.ConfidenceLevel.GetName()}'. Its embedding provider '{embeddingProvider.Name}' only has confidence '{embeddingProviderConfidence.GetName()}'. We skip this source."); + this.logger.LogWarning($"The internal data source '{source.Name}' (id={source.Id}) requires provider confidence '{internalSource.ConfidenceLevel.Name}'. Its embedding provider '{embeddingProvider.Name}' only has confidence '{embeddingProviderConfidence.Name}'. We skip this source."); return null; } diff --git a/app/MindWork AI Studio/Tools/Services/Indexing/DocumentRunProgress.cs b/app/MindWork AI Studio/Tools/Services/Indexing/DocumentRunProgress.cs index 5dcc3d976..5f4e323cd 100644 --- a/app/MindWork AI Studio/Tools/Services/Indexing/DocumentRunProgress.cs +++ b/app/MindWork AI Studio/Tools/Services/Indexing/DocumentRunProgress.cs @@ -332,7 +332,7 @@ internal sealed class DocumentRunProgress(IndexedRunContext context, int totalDo break; } - case FileExtractionException extractionFailure when extractionFailure.Code.IsPermanentIndexingFailure(): + case FileExtractionException extractionFailure when extractionFailure.Code.IsPermanentIndexingFailure: { // // The document itself is why this failed, so trying it again changes nothing until diff --git a/app/MindWork AI Studio/Tools/Services/Indexing/MailboxIndexer.cs b/app/MindWork AI Studio/Tools/Services/Indexing/MailboxIndexer.cs index d7fcc65f6..7c5f173ea 100644 --- a/app/MindWork AI Studio/Tools/Services/Indexing/MailboxIndexer.cs +++ b/app/MindWork AI Studio/Tools/Services/Indexing/MailboxIndexer.cs @@ -118,7 +118,7 @@ internal sealed partial class MailboxIndexer(SettingsManager settingsManager, Ru if (!policy.IsAllowed(mailbox.Host)) { logger.LogInformation("Not connecting to mailbox '{MailboxId}' because the organization allows only its own mail servers, and this one is none of them.", mailbox.Id); - (await this.CreateStoredStateProgressAsync(context, token)).PublishRunFailure(MailboxConnectionFailure.SERVER_NOT_ALLOWED.GetDescription(), DataSourceAttention.SERVER_NOT_ALLOWED); + (await this.CreateStoredStateProgressAsync(context, token)).PublishRunFailure(MailboxConnectionFailure.SERVER_NOT_ALLOWED.Description, DataSourceAttention.SERVER_NOT_ALLOWED); return IndexedRunOutcome.DONE; } @@ -170,7 +170,7 @@ internal sealed partial class MailboxIndexer(SettingsManager settingsManager, Ru progress.PublishRunFailure(GetAuthFailureMessage(failure), DataSourceAttention.AUTH_FAILED); } else - progress.PublishRunFailure(e.Failure.GetDescription(), e.Failure is MailboxConnectionFailure.SERVER_NOT_ALLOWED ? DataSourceAttention.SERVER_NOT_ALLOWED : DataSourceAttention.NONE); + progress.PublishRunFailure(e.Failure.Description, e.Failure is MailboxConnectionFailure.SERVER_NOT_ALLOWED ? DataSourceAttention.SERVER_NOT_ALLOWED : DataSourceAttention.NONE); return IndexedRunOutcome.DONE; } @@ -307,7 +307,7 @@ internal sealed partial class MailboxIndexer(SettingsManager settingsManager, Ru this.RecordConnectionFailure(mailbox.Id, e.Failure); await context.OptimizeCollectionIfNeededAsync("mailbox sync stopped", token); progress ??= await this.CreateStoredStateProgressAsync(context, token); - progress.PublishRunFailure(e.Failure.GetDescription()); + progress.PublishRunFailure(e.Failure.Description); return IndexedRunOutcome.DONE; } } diff --git a/app/MindWork AI Studio/Tools/Services/MediaTranscriptionService.cs b/app/MindWork AI Studio/Tools/Services/MediaTranscriptionService.cs index d66738ab7..fd649990f 100644 --- a/app/MindWork AI Studio/Tools/Services/MediaTranscriptionService.cs +++ b/app/MindWork AI Studio/Tools/Services/MediaTranscriptionService.cs @@ -690,7 +690,7 @@ public sealed class MediaTranscriptionService( // unchanged when it already is a single mono 48 kHz Opus track in a WebM container and small // enough. Such a file keeps whatever bitrate it was made with, which is the better outcome -- // re-encoding it could only take quality away, never add any. - var opusBitrateBps = settingsManager.ConfigurationData.App.OpusBitrate.GetBitsPerSecond(); + var opusBitrateBps = settingsManager.ConfigurationData.App.OpusBitrate.BitsPerSecond; // Which quality an upload was produced with is the first question to ask when a transcript // comes back missing something, so it has to be in the log of the job it belongs to: diff --git a/app/MindWork AI Studio/Tools/Services/PluginInstallService.Delete.cs b/app/MindWork AI Studio/Tools/Services/PluginInstallService.Delete.cs index df5390a1d..0e15024cf 100644 --- a/app/MindWork AI Studio/Tools/Services/PluginInstallService.Delete.cs +++ b/app/MindWork AI Studio/Tools/Services/PluginInstallService.Delete.cs @@ -247,7 +247,7 @@ public sealed partial class PluginInstallService private static string CreateDeleteBackupDirectory(IAvailablePlugin plugin) { var backupRoot = Path.Join(SettingsManager.DataDirectory, DELETE_BACKUP_DIRECTORY); - return Path.Join(backupRoot, $"{plugin.Type.GetDirectory()}-{plugin.Id:N}-{Guid.NewGuid():N}"); + return Path.Join(backupRoot, $"{plugin.Type.Directory}-{plugin.Id:N}-{Guid.NewGuid():N}"); } private async Task TryRestoreDeletedPluginAsync(IAvailablePlugin plugin, string pluginDirectory, string backupDirectory, PluginDeleteSideEffects sideEffects, CancellationToken token) diff --git a/app/MindWork AI Studio/Tools/Services/PluginInstallService.Installation.cs b/app/MindWork AI Studio/Tools/Services/PluginInstallService.Installation.cs index 98839de5d..fc2574d5e 100644 --- a/app/MindWork AI Studio/Tools/Services/PluginInstallService.Installation.cs +++ b/app/MindWork AI Studio/Tools/Services/PluginInstallService.Installation.cs @@ -133,7 +133,7 @@ public sealed partial class PluginInstallService return false; } - pluginRoot = Path.Join(dataDirectory, "plugins", pluginType.GetDirectory()); + pluginRoot = Path.Join(dataDirectory, "plugins", pluginType.Directory); return true; } diff --git a/app/MindWork AI Studio/Tools/Services/RustService.APIKeys.cs b/app/MindWork AI Studio/Tools/Services/RustService.APIKeys.cs index befcca6f3..d9909275a 100644 --- a/app/MindWork AI Studio/Tools/Services/RustService.APIKeys.cs +++ b/app/MindWork AI Studio/Tools/Services/RustService.APIKeys.cs @@ -10,15 +10,15 @@ public sealed partial class RustService // documentation/compatibility-shims/2026-06-self-hosted-secret-id.md private const string LEGACY_SELF_HOSTED_SECRET_ID_DE = "Selbst gehostet"; - private static string APIKey(SecretStoreType storeType, ISecretId secretId) => $"{storeType.Prefix()}::{secretId.SecretId}::{secretId.SecretName}::api_key"; + private static string APIKey(SecretStoreType storeType, ISecretId secretId) => $"{storeType.Prefix}::{secretId.SecretId}::{secretId.SecretName}::api_key"; private static IEnumerable LegacySelfHostedAPIKeys(ISecretId secretId, SecretStoreType storeType) { if (secretId.SecretId == SELF_HOSTED_SECRET_ID) - yield return $"{storeType.Prefix()}::{LEGACY_SELF_HOSTED_SECRET_ID_DE}::{secretId.SecretName}::api_key"; + yield return $"{storeType.Prefix}::{LEGACY_SELF_HOSTED_SECRET_ID_DE}::{secretId.SecretName}::api_key"; if (secretId.SecretId == $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{SELF_HOSTED_SECRET_ID}") - yield return $"{storeType.Prefix()}::{ISecretId.ENTERPRISE_KEY_PREFIX}::{LEGACY_SELF_HOSTED_SECRET_ID_DE}::{secretId.SecretName}::api_key"; + yield return $"{storeType.Prefix}::{ISecretId.ENTERPRISE_KEY_PREFIX}::{LEGACY_SELF_HOSTED_SECRET_ID_DE}::{secretId.SecretName}::api_key"; } /// diff --git a/app/MindWork AI Studio/Tools/Services/RustService.Secrets.cs b/app/MindWork AI Studio/Tools/Services/RustService.Secrets.cs index 81c1495fc..413e5e721 100644 --- a/app/MindWork AI Studio/Tools/Services/RustService.Secrets.cs +++ b/app/MindWork AI Studio/Tools/Services/RustService.Secrets.cs @@ -24,7 +24,7 @@ public sealed partial class RustService private static DeleteSecretResponse TranslateSecretStoreIssue(DeleteSecretResponse response) => response.Success ? response : response with { Issue = TranslateSecretStoreIssue(response.IssueCode, response.Issue) }; - private static string SecretKey(ISecretId secretId, SecretStoreType storeType) => $"{storeType.Prefix()}::{secretId.SecretId}::{secretId.SecretName}"; + private static string SecretKey(ISecretId secretId, SecretStoreType storeType) => $"{storeType.Prefix}::{secretId.SecretId}::{secretId.SecretName}"; private static string LegacySecretKey(ISecretId secretId) => $"secret::{secretId.SecretId}::{secretId.SecretName}"; diff --git a/app/MindWork AI Studio/Tools/SourceCodeLanguages.cs b/app/MindWork AI Studio/Tools/SourceCodeLanguages.cs index f583f012d..b6bba0e9f 100644 --- a/app/MindWork AI Studio/Tools/SourceCodeLanguages.cs +++ b/app/MindWork AI Studio/Tools/SourceCodeLanguages.cs @@ -12,7 +12,7 @@ namespace AIStudio.Tools; /// Models do not agree on how they spell a language: Python comes as python, py, or Python3. The /// catalog therefore knows the usual aliases, the way GitHub Linguist and highlight.js spell them, /// in any case. The formats AI Studio writes as formats of their own, such as html, latex, markdown, -/// or csv, are missing on purpose: FileExportFormatExtensions.TryFromCodeFenceLanguage reads them +/// or csv, are missing on purpose: FileExportFormat.TryFromCodeFenceLanguage reads them /// first, and a file in one of them is treated apart from code, it takes the sources of the answer /// along, for example. Each language has exactly one extension; whoever needs another one renames /// the file. diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/SafeSearchPolicyExtensions.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/SafeSearchPolicyExtensions.cs index dd232b97c..c6cae7cb7 100644 --- a/app/MindWork AI Studio/Tools/ToolCallingSystem/SafeSearchPolicyExtensions.cs +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/SafeSearchPolicyExtensions.cs @@ -11,7 +11,7 @@ public static class SafeSearchPolicyExtensions /// SearXNG takes the level as a number. That number stays here, at the edge towards the /// search engine, instead of travelling through the settings where nobody can read it. /// - public string ToSearXNGValue() => policy switch + public string SearXNGValue => policy switch { SafeSearchPolicy.OFF => "0", SafeSearchPolicy.MODERATE => "1", @@ -28,6 +28,6 @@ public static class SafeSearchPolicyExtensions /// a strict one. Of the two ways to round that, filtering more than was asked for is the one /// that cannot surprise anyone. /// - public bool ToTavilyValue() => policy is not SafeSearchPolicy.OFF; + public bool TavilyValue => policy is not SafeSearchPolicy.OFF; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/ReadWebPageTool.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/ReadWebPageTool.cs index 97935567e..5f2887bc2 100644 --- a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/ReadWebPageTool.cs +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/ReadWebPageTool.cs @@ -129,7 +129,7 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ MAX_CONTENT_CHARACTERS_SETTING => TB("(Optional) Global truncation limit for extracted characters returned to the model."), ALLOWED_PRIVATE_HOSTS_SETTING => TB("(Optional) Host allowlist for private or VPN web pages. For security reasons, private or VPN web pages aren't allowed to be read by default. Separate host patterns with commas, such as example.de, *.example.de. Allowed private hosts require a High-confidence provider. For allowed HTTPS internal hosts, AI Studio also tries the operating system's default sign-in automatically when the server responds with integrated authentication."), FREE_ADDRESS_CHOICE_SETTING => TB("(Optional) With free address choice off, the AI reads only web addresses that appear in the chat, such as in your messages, attached documents, or data sources, or that a tool returned. AI Studio refuses every other address. With it on, the AI may also choose addresses itself. Off is the default."), - INTERNAL_PAGE_OUTBOUND_DATA_RESTRICTION_SETTING => string.Format(TB("(Optional) Internal pages are web pages on a private or VPN address and the pages of your Confluence wiki, whatever its address. Once a chat read one, or searched your wiki, a web search or a web address chosen by the AI could carry internal content to third parties. This setting decides what the chat may still use afterwards. With '{0}', the default, the chat does not search the web, but it still reads web pages whose addresses stand in the chat. With '{1}', it reads only pages of your Confluence wiki and of the allowed private hosts. A change applies to pages read later; a chat keeps the level it had when it read a page."), OutboundDataRestriction.ONLY_LINKS_FROM_CHAT.GetName(), OutboundDataRestriction.ONLY_CONFIGURED_SERVICES.GetName()), + INTERNAL_PAGE_OUTBOUND_DATA_RESTRICTION_SETTING => string.Format(TB("(Optional) Internal pages are web pages on a private or VPN address and the pages of your Confluence wiki, whatever its address. Once a chat read one, or searched your wiki, a web search or a web address chosen by the AI could carry internal content to third parties. This setting decides what the chat may still use afterwards. With '{0}', the default, the chat does not search the web, but it still reads web pages whose addresses stand in the chat. With '{1}', it reads only pages of your Confluence wiki and of the allowed private hosts. A change applies to pages read later; a chat keeps the level it had when it read a page."), OutboundDataRestriction.ONLY_LINKS_FROM_CHAT.Name, OutboundDataRestriction.ONLY_CONFIGURED_SERVICES.Name), _ => TB(fieldDefinition.Description), }; @@ -266,7 +266,7 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ /// turn into ON without anybody having written it, see EnumNames. The configuration check /// reports such a value anyway and keeps the tool out of use until somebody corrects it. /// - internal static FreeAddressChoice ReadFreeAddressChoice(string? configuredValue) => EnumNames.TryParse(configuredValue, out var freeAddressChoice) ? freeAddressChoice : DEFAULT_FREE_ADDRESS_CHOICE; + internal static FreeAddressChoice ReadFreeAddressChoice(string? configuredValue) => FreeAddressChoice.TryParseName(configuredValue, out var freeAddressChoice) ? freeAddressChoice : DEFAULT_FREE_ADDRESS_CHOICE; /// /// Words the rules the model follows when it reads web pages. @@ -517,7 +517,7 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ if (string.IsNullOrWhiteSpace(configuredValue)) return DEFAULT_INTERNAL_PAGE_OUTBOUND_DATA_RESTRICTION; - return EnumNames.TryParse(configuredValue, out var restriction) ? restriction : OutboundDataRestriction.ONLY_CONFIGURED_SERVICES; + return OutboundDataRestriction.TryParseName(configuredValue, out var restriction) ? restriction : OutboundDataRestriction.ONLY_CONFIGURED_SERVICES; } /// diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/SearXNG/SearXNGSearchBackend.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/SearXNG/SearXNGSearchBackend.cs index 76a2d077d..84642ca94 100644 --- a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/SearXNG/SearXNGSearchBackend.cs +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/SearXNG/SearXNGSearchBackend.cs @@ -76,7 +76,7 @@ public sealed class SearXNGSearchBackend : IWebSearchBackend // No configured policy sends nothing at all, which leaves the decision to the // instance's own configuration: - var safeSearch = query.SafeSearch?.ToSearXNGValue(); + var safeSearch = query.SafeSearch?.SearXNGValue; var response = await this.searchClient.SearchAsync(new SearXNGSearchRequest(searchUri, query.Query, query.Language, query.TimeRange, query.Page, safeSearch, query.Limit, query.TimeoutSeconds), token); // diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/Tavily/TavilySearchBackend.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/Tavily/TavilySearchBackend.cs index cc2f373be..a4f51f952 100644 --- a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/Tavily/TavilySearchBackend.cs +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/Tavily/TavilySearchBackend.cs @@ -133,7 +133,7 @@ public sealed class TavilySearchBackend : IWebSearchBackend // would rather have more hits than one language can choose any language instead. // FilterByLanguage = language is null ? null : true, - SafeSearch = query.SafeSearch?.ToTavilyValue(), + SafeSearch = query.SafeSearch?.TavilyValue, }; var response = await this.searchClient.SearchAsync(apiKey.Trim(), searchRequest, query.TimeoutSeconds, token); diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchBackendExtensions.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchBackendExtensions.cs index 13a74d4ae..db46ee05c 100644 --- a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchBackendExtensions.cs +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchBackendExtensions.cs @@ -13,7 +13,7 @@ public static class WebSearchBackendExtensions /// worded for people — in the settings dropdown, in a note explaining which service /// answered, and in the result the model reads. /// - public string ToName() => backend switch + public string Name => backend switch { WebSearchBackend.SEARXNG => "SearXNG", WebSearchBackend.STAAN => "Staan", diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchDispatcher.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchDispatcher.cs index 487364042..3a6aa2826 100644 --- a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchDispatcher.cs +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchDispatcher.cs @@ -80,7 +80,7 @@ internal sealed class WebSearchDispatcher(IEnumerable backend if (usesChosenBackend && chosenBackend is null && configuredBackends.Count > 1) { if (primaryBackend is not null) - notes.Add($"The chosen search service {primaryBackend.Value.ToName()} is not configured, so the configured services were asked one after another instead."); + notes.Add($"The chosen search service {primaryBackend.Value.Name} is not configured, so the configured services were asked one after another instead."); else if (strategy is WebSearchBackendStrategy.SPECIFIC) notes.Add("No search service is chosen, so the configured services were asked one after another instead."); } @@ -118,7 +118,7 @@ internal sealed class WebSearchDispatcher(IEnumerable backend throw new InvalidOperationException(TB("None of the search services this search would use can filter explicit results, which the configured safe search policy requires. Please configure a search service that can filter, or turn the policy off.")); foreach (var backend in backendsToAsk.Where(backend => !backend.Capabilities.SupportsSafeSearch)) - notes.Add($"{backend.Backend.ToName()} was not asked, because it cannot filter explicit results and the configured safe search policy requires that."); + notes.Add($"{backend.Backend.Name} was not asked, because it cannot filter explicit results and the configured safe search policy requires that."); return remainingBackends; } @@ -141,7 +141,7 @@ internal sealed class WebSearchDispatcher(IEnumerable backend throw new ArgumentException($"Argument 'page' must be less than or equal to {backendsToAsk.Max(backend => backend.Capabilities.MaxPage)}."); foreach (var backend in backendsToAsk.Where(backend => query.Page > backend.Capabilities.MaxPage)) - notes.Add($"{backend.Backend.ToName()} was not asked, because it does not serve result page {query.Page}."); + notes.Add($"{backend.Backend.Name} was not asked, because it does not serve result page {query.Page}."); return remainingBackends; } @@ -205,7 +205,7 @@ internal sealed class WebSearchDispatcher(IEnumerable backend var attributesNotes = outcomes.Count > 1; foreach (var outcome in outcomes) { - var backendName = outcome.Backend.Backend.ToName(); + var backendName = outcome.Backend.Backend.Name; var result = outcome.Result; if (result is null) { @@ -236,7 +236,7 @@ internal sealed class WebSearchDispatcher(IEnumerable backend /// private static void AppendUnsupportedFilterNotes(List notes, IWebSearchBackend backend, WebSearchQuery query) { - var backendName = backend.Backend.ToName(); + var backendName = backend.Backend.Name; var capabilities = backend.Capabilities; if (!capabilities.SupportsTimeRange && !string.IsNullOrWhiteSpace(query.TimeRange)) notes.Add($"{backendName} cannot restrict a search to a period of time, so its hits are not limited to the requested time range '{query.TimeRange}'."); diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchTool.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchTool.cs index c27d4e75c..35b78eb3f 100644 --- a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchTool.cs +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchTool.cs @@ -286,7 +286,7 @@ public sealed class WebSearchTool(IEnumerable backends, WebPa var unfilteredBackends = this.dispatcher.GetConfiguredBackends(settingsValues) .Where(backend => !backend.Capabilities.SupportsSafeSearch) - .Select(backend => backend.Backend.ToName()) + .Select(backend => backend.Backend.Name) .ToList(); if (unfilteredBackends.Count is 0) @@ -362,7 +362,7 @@ public sealed class WebSearchTool(IEnumerable backends, WebPa return Task.FromResult(new ToolConfigurationState { IsConfigured = false, - Message = string.Format(TB("The preferred search service {0} is not configured. Please configure it, or choose one of the services you did configure."), primaryBackend.Value.ToName()), + Message = string.Format(TB("The preferred search service {0} is not configured. Please configure it, or choose one of the services you did configure."), primaryBackend.Value.Name), }); } @@ -429,7 +429,7 @@ public sealed class WebSearchTool(IEnumerable backends, WebPa return Task.FromResult(new ToolConfigurationState { IsConfigured = false, - Message = string.Format(TB("The preferred search service {0} cannot filter explicit results, but a safe search policy is configured and it is the only service that would be used. Please choose another service, let the services be used one after another, or set the safe search policy to off."), chosenBackend.Value.ToName()), + Message = string.Format(TB("The preferred search service {0} cannot filter explicit results, but a safe search policy is configured and it is the only service that would be used. Please choose another service, let the services be used one after another, or set the safe search policy to off."), chosenBackend.Value.Name), }); } } @@ -612,7 +612,7 @@ public sealed class WebSearchTool(IEnumerable backends, WebPa // what tells apart a thin answer from one search service having nothing to say and // a thin answer from the others never having been asked. // - ["backends"] = BuildJsonArray(searchResponse.Backends.Select(backend => backend.ToName())), + ["backends"] = BuildJsonArray(searchResponse.Backends.Select(backend => backend.Name)), ["candidate_count"] = searchResponse.CandidateCount, ["result_count"] = retrievalResult.Results.Count, @@ -654,7 +654,7 @@ public sealed class WebSearchTool(IEnumerable backends, WebPa "Completed web search. ToolCallId={ToolCallId}, Strategy={Strategy}, Backends={Backends}, CandidateCount={CandidateCount}, ResultCount={ResultCount}, RetrievedPageCount={RetrievedPageCount}, BlockedPageCount={BlockedPageCount}, PageTimeoutCount={PageTimeoutCount}, FailedPageCount={FailedPageCount}, EmptyContentCount={EmptyContentCount}, RetrievalTimedOut={RetrievalTimedOut}, ReturnedContentCharacters={ReturnedContentCharacters}, TruncatedResultCount={TruncatedResultCount}, Notes={Notes}", context.ToolCallId, backendStrategy, - string.Join(", ", searchResponse.Backends.Select(backend => backend.ToName())), + string.Join(", ", searchResponse.Backends.Select(backend => backend.Name)), searchResponse.CandidateCount, retrievalResult.Results.Count, retrievedPageCount, @@ -694,7 +694,7 @@ public sealed class WebSearchTool(IEnumerable backends, WebPa private static WebSearchBackendStrategy ReadBackendStrategy(IReadOnlyDictionary settingsValues) { var configuredStrategy = settingsValues.GetValueOrDefault(BACKEND_STRATEGY_SETTING); - return EnumNames.TryParse(configuredStrategy, out var strategy) ? strategy : DEFAULT_BACKEND_STRATEGY; + return WebSearchBackendStrategy.TryParseName(configuredStrategy, out var strategy) ? strategy : DEFAULT_BACKEND_STRATEGY; } /// @@ -708,7 +708,7 @@ public sealed class WebSearchTool(IEnumerable backends, WebPa private static WebSearchBackend? ReadPrimaryBackend(IReadOnlyDictionary settingsValues) { var configuredBackend = settingsValues.GetValueOrDefault(PRIMARY_BACKEND_SETTING); - return EnumNames.TryParse(configuredBackend, out var backend) ? backend : null; + return WebSearchBackend.TryParseName(configuredBackend, out var backend) ? backend : null; } private static JsonObject BuildResultJson(WebSearchPageResult result, WebPageModelContent sanitizedContent) @@ -719,7 +719,7 @@ public sealed class WebSearchTool(IEnumerable backends, WebPa // Two services having found the same page says something about the page that // neither of them says alone, so it is reported per hit and not only per search: - ["backends"] = BuildJsonArray(result.Candidate.Backends.Select(backend => backend.ToName())), + ["backends"] = BuildJsonArray(result.Candidate.Backends.Select(backend => backend.Name)), }; // @@ -875,6 +875,6 @@ public sealed class WebSearchTool(IEnumerable backends, WebPa private static SafeSearchPolicy? ReadSafeSearchPolicy(IReadOnlyDictionary settingsValues) { var configuredPolicy = settingsValues.GetValueOrDefault(DEFAULT_SAFE_SEARCH_SETTING); - return EnumNames.TryParse(configuredPolicy, out var policy) ? policy : null; + return SafeSearchPolicy.TryParseName(configuredPolicy, out var policy) ? policy : null; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolSettingsOptionSources.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolSettingsOptionSources.cs index 07c6187d8..8b122f76f 100644 --- a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolSettingsOptionSources.cs +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolSettingsOptionSources.cs @@ -100,7 +100,7 @@ public static class ToolSettingsOptionSources // translation. Adding a search service therefore adds it to this list, and to the // dropdown offering it, without a line of code here: // - WEB_SEARCH_BACKENDS => Enum.GetValues().Select(backend => new ToolSettingsOption(backend.ToString(), backend.ToName())).ToList(), + WEB_SEARCH_BACKENDS => Enum.GetValues().Select(backend => new ToolSettingsOption(backend.ToString(), backend.Name)).ToList(), WEB_SEARCH_BACKEND_STRATEGY => [ new(nameof(WebSearchBackendStrategy.FAILOVER), TB("One after another, until one answers")), @@ -114,7 +114,7 @@ public static class ToolSettingsOptionSources new(nameof(FreeAddressChoice.ON), TB("On: the AI may also choose web addresses itself")), ], - OUTBOUND_DATA_RESTRICTION => Enum.GetValues().Select(restriction => new ToolSettingsOption(restriction.ToString(), restriction.GetName())).ToList(), + OUTBOUND_DATA_RESTRICTION => Enum.GetValues().Select(restriction => new ToolSettingsOption(restriction.ToString(), restriction.Name)).ToList(), _ => [], }; @@ -136,9 +136,9 @@ public static class ToolSettingsOptionSources // user may keep a text as it is or type a language of their own. A search engine needs // a concrete tag, and ANY_LANGUAGE above already covers "no preference". // - var tag = language.ToIETFTag(); + var tag = language.IETFTag; if (!string.IsNullOrWhiteSpace(tag)) - options.Add(new(tag, language.Name())); + options.Add(new(tag, language.Name)); } return options; diff --git a/app/MindWork AI Studio/Tools/Validation/DataSourceValidation.cs b/app/MindWork AI Studio/Tools/Validation/DataSourceValidation.cs index ce88b2e02..5252898ff 100644 --- a/app/MindWork AI Studio/Tools/Validation/DataSourceValidation.cs +++ b/app/MindWork AI Studio/Tools/Validation/DataSourceValidation.cs @@ -209,8 +209,8 @@ public sealed class DataSourceValidation if(confidenceLevel is ConfidenceLevel.NONE) return TB("Please select a required provider confidence level."); - if(!confidenceLevel.IsAllowedMailboxConfidence()) - return string.Format(TB("A mailbox requires a provider confidence level from '{0}' to '{1}'."), ConfidenceLevel.VERY_LOW.GetName(), ConfidenceLevel.HIGH.GetName()); + if(!confidenceLevel.IsAllowedMailboxConfidence) + return string.Format(TB("A mailbox requires a provider confidence level from '{0}' to '{1}'."), ConfidenceLevel.VERY_LOW.Name, ConfidenceLevel.HIGH.Name); return this.ValidateSelectedEmbeddingProviderAccess(); } @@ -305,7 +305,7 @@ public sealed class DataSourceValidation return string.Format( TB("The selected embedding provider has confidence '{0}', but this data source requires provider confidence '{1}'. Select an embedding provider with equal or higher confidence or lower the required confidence level."), - selectedEmbedding.GetConfidenceLevel(settingsManager).GetName(), - confidenceLevel.GetName()); + selectedEmbedding.GetConfidenceLevel(settingsManager).Name, + confidenceLevel.Name); } } diff --git a/app/MindWork AI Studio/Tools/Validation/ProviderValidation.cs b/app/MindWork AI Studio/Tools/Validation/ProviderValidation.cs index 10b775e61..ad87de415 100644 --- a/app/MindWork AI Studio/Tools/Validation/ProviderValidation.cs +++ b/app/MindWork AI Studio/Tools/Validation/ProviderValidation.cs @@ -131,7 +131,7 @@ public sealed class ProviderValidation if(this.GetProvider() is not LLMProviders.HUGGINGFACE) return null; - if (!inferenceProvider.SupportsChat()) + if (!inferenceProvider.SupportsChat) return TB("Please select an Hugging Face inference provider."); return null; @@ -165,7 +165,7 @@ public sealed class ProviderValidation if (inferenceProvider is HFInferenceProvider.NONE) return TB("Please select an Hugging Face inference provider."); - if (!inferenceProvider.SupportsEmbeddings()) + if (!inferenceProvider.SupportsEmbeddings) return TB("This Hugging Face inference provider does not create embeddings. Please select another one."); return null; @@ -188,7 +188,7 @@ public sealed class ProviderValidation if (inferenceProvider is HFInferenceProvider.NONE) return TB("Please select an Hugging Face inference provider."); - if (!inferenceProvider.SupportsTranscription()) + if (!inferenceProvider.SupportsTranscription) return TB("This Hugging Face inference provider does not transcribe audio. Please select another one."); return null; diff --git a/app/SharedTools/RIDExtensions.cs b/app/SharedTools/RIDExtensions.cs index 8e17465b9..9ad38b336 100644 --- a/app/SharedTools/RIDExtensions.cs +++ b/app/SharedTools/RIDExtensions.cs @@ -4,39 +4,42 @@ namespace SharedTools; public static class RIDExtensions { - /// - /// Detects the current Runtime Identifier (RID) at runtime based on OS and architecture. - /// - /// - /// This is the machine which runs the code. The architecture in the metadata of AI Studio - /// is the platform AI Studio was built for instead; both can differ under emulation. - /// - /// The detected RID for the current platform. - public static RID GetCurrentRID() - { - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); - var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); - var arch = RuntimeInformation.OSArchitecture; - - return (isWindows, isLinux, isMacOS, arch) switch - { - (true, _, _, Architecture.X64) => RID.WIN_X64, - (true, _, _, Architecture.Arm64) => RID.WIN_ARM64, - - (_, true, _, Architecture.X64) => RID.LINUX_X64, - (_, true, _, Architecture.Arm64) => RID.LINUX_ARM64, - - (_, _, true, Architecture.X64) => RID.OSX_X64, - (_, _, true, Architecture.Arm64) => RID.OSX_ARM64, - - _ => RID.NONE, - }; - } - extension(RID rid) { - public string AsMicrosoftRid() => rid switch + /// + /// Detects the current Runtime Identifier (RID) at runtime based on OS and architecture. + /// + /// + /// This is the machine which runs the code. The architecture in the metadata of AI Studio + /// is the platform AI Studio was built for instead; both can differ under emulation. + /// + /// The detected RID for the current platform. + public static RID Current + { + get + { + var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + var arch = RuntimeInformation.OSArchitecture; + + return (isWindows, isLinux, isMacOS, arch) switch + { + (true, _, _, Architecture.X64) => RID.WIN_X64, + (true, _, _, Architecture.Arm64) => RID.WIN_ARM64, + + (_, true, _, Architecture.X64) => RID.LINUX_X64, + (_, true, _, Architecture.Arm64) => RID.LINUX_ARM64, + + (_, _, true, Architecture.X64) => RID.OSX_X64, + (_, _, true, Architecture.Arm64) => RID.OSX_ARM64, + + _ => RID.NONE, + }; + } + } + + public string MicrosoftRid => rid switch { RID.WIN_X64 => "win-x64", RID.WIN_ARM64 => "win-arm64", @@ -50,7 +53,7 @@ public static class RIDExtensions _ => string.Empty, }; - public string ToUserFriendlyName() => rid switch + public string UserFriendlyName => rid switch { RID.WIN_X64 => "Windows x64", RID.WIN_ARM64 => "Windows ARM64", diff --git a/app/SourceCodeRules/SourceCodeRules/StyleAnalyzers/SwitchExpressionMethodAnalyzer.cs b/app/SourceCodeRules/SourceCodeRules/StyleAnalyzers/SwitchExpressionMethodAnalyzer.cs index 2bd7f80e0..574ffc968 100644 --- a/app/SourceCodeRules/SourceCodeRules/StyleAnalyzers/SwitchExpressionMethodAnalyzer.cs +++ b/app/SourceCodeRules/SourceCodeRules/StyleAnalyzers/SwitchExpressionMethodAnalyzer.cs @@ -14,11 +14,11 @@ public class SwitchExpressionMethodAnalyzer : DiagnosticAnalyzer { private const string DIAGNOSTIC_ID = Identifier.SWITCH_EXPRESSION_METHOD_ANALYZER; - private static readonly string TITLE = "Method with switch expression should use inline expression body"; + private static readonly string TITLE = "Method or property with switch expression should use inline expression body"; - private static readonly string MESSAGE_FORMAT = "Method with a switch expression should use inline expression body syntax with the switch keyword on the same line"; + private static readonly string MESSAGE_FORMAT = "{0} with a switch expression should use inline expression body syntax with the switch keyword on the same line"; - private static readonly string DESCRIPTION = "Methods that only return a switch expression should use the expression body syntax (=>) with the switch keyword on the same line for better readability."; + private static readonly string DESCRIPTION = "Methods and properties that only return a switch expression should use the expression body syntax (=>) with the switch keyword on the same line for better readability."; private const string CATEGORY = "Style"; @@ -38,59 +38,54 @@ public class SwitchExpressionMethodAnalyzer : DiagnosticAnalyzer context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); context.RegisterSyntaxNodeAction(AnalyzeMethodDeclaration, SyntaxKind.MethodDeclaration); + context.RegisterSyntaxNodeAction(AnalyzePropertyDeclaration, SyntaxKind.PropertyDeclaration); } private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context) { var methodDeclaration = (MethodDeclarationSyntax)context.Node; - - // Fall 1: Methode hat Block-Body mit einem Return-Statement, das eine Switch-Expression ist - if (methodDeclaration is { Body: not null, ExpressionBody: null }) - { - var statements = methodDeclaration.Body.Statements; - if (statements.Count == 1 && statements[0] is ReturnStatementSyntax { Expression: SwitchExpressionSyntax }) - { - var diagnostic = Diagnostic.Create(RULE, methodDeclaration.Identifier.GetLocation()); - context.ReportDiagnostic(diagnostic); - return; - } - } - - // Fall 2: Methode hat Expression-Body, aber die Switch-Expression beginnt auf einer neuen Zeile - var expressionBody = methodDeclaration.ExpressionBody; - if (expressionBody?.Expression is SwitchExpressionSyntax switchExpr) - { - var arrowToken = expressionBody.ArrowToken; - var switchToken = switchExpr.SwitchKeyword; - bool hasNewLineBetweenArrowAndSwitch = false; - - foreach (var trivia in arrowToken.TrailingTrivia) - { - if (trivia.IsKind(SyntaxKind.EndOfLineTrivia)) - { - hasNewLineBetweenArrowAndSwitch = true; - break; - } - } - - // Prüfe Leading Trivia des Switch-Keywords, falls notwendig - if (!hasNewLineBetweenArrowAndSwitch) - { - foreach (var trivia in switchToken.LeadingTrivia) - { - if (trivia.IsKind(SyntaxKind.EndOfLineTrivia)) - { - hasNewLineBetweenArrowAndSwitch = true; - break; - } - } - } - - if (hasNewLineBetweenArrowAndSwitch) - { - var diagnostic = Diagnostic.Create(RULE, methodDeclaration.Identifier.GetLocation()); - context.ReportDiagnostic(diagnostic); - } - } + if (NeedsInlineExpressionBody(methodDeclaration.Body, methodDeclaration.ExpressionBody)) + context.ReportDiagnostic(Diagnostic.Create(RULE, methodDeclaration.Identifier.GetLocation(), "Method")); } + + private static void AnalyzePropertyDeclaration(SyntaxNodeAnalysisContext context) + { + var propertyDeclaration = (PropertyDeclarationSyntax)context.Node; + if (propertyDeclaration.ExpressionBody is not null) + { + if (NeedsInlineExpressionBody(null, propertyDeclaration.ExpressionBody)) + context.ReportDiagnostic(Diagnostic.Create(RULE, propertyDeclaration.Identifier.GetLocation(), "Property")); + + return; + } + + // + // A property with nothing but a getter which returns a switch expression says the same as one with + // an expression body. Its getter is no place for the switch, wherever the keyword stands: + // + if (propertyDeclaration.AccessorList is not { Accessors.Count: 1 } accessorList) + return; + + var getter = accessorList.Accessors[0]; + if (!getter.IsKind(SyntaxKind.GetAccessorDeclaration) || getter.AttributeLists.Count > 0 || getter.Modifiers.Count > 0) + return; + + if (getter.ExpressionBody?.Expression is SwitchExpressionSyntax || ReturnsOnlySwitchExpression(getter.Body)) + context.ReportDiagnostic(Diagnostic.Create(RULE, propertyDeclaration.Identifier.GetLocation(), "Property")); + } + + private static bool NeedsInlineExpressionBody(BlockSyntax? body, ArrowExpressionClauseSyntax? expressionBody) + { + // Case 1: a block body with nothing but a return of a switch expression: + if (body is not null && expressionBody is null) + return ReturnsOnlySwitchExpression(body); + + // Case 2: an expression body whose switch expression starts on a new line: + if (expressionBody?.Expression is not SwitchExpressionSyntax switchExpression) + return false; + + return expressionBody.ArrowToken.TrailingTrivia.Any(SyntaxKind.EndOfLineTrivia) || switchExpression.SwitchKeyword.LeadingTrivia.Any(SyntaxKind.EndOfLineTrivia); + } + + private static bool ReturnsOnlySwitchExpression(BlockSyntax? body) => body is { Statements.Count: 1 } && body.Statements[0] is ReturnStatementSyntax { Expression: SwitchExpressionSyntax }; } \ No newline at end of file diff --git a/app/SourceCodeRules/SourceCodeRules/StyleCodeFixes/SwitchExpressionMethodCodeFixProvider.cs b/app/SourceCodeRules/SourceCodeRules/StyleCodeFixes/SwitchExpressionMethodCodeFixProvider.cs index d89751ffc..257f475f1 100644 --- a/app/SourceCodeRules/SourceCodeRules/StyleCodeFixes/SwitchExpressionMethodCodeFixProvider.cs +++ b/app/SourceCodeRules/SourceCodeRules/StyleCodeFixes/SwitchExpressionMethodCodeFixProvider.cs @@ -28,100 +28,97 @@ public class SwitchExpressionMethodCodeFixProvider : CodeFixProvider var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; - var methodDeclaration = root.FindToken(diagnosticSpan.Start) + var memberDeclaration = root.FindToken(diagnosticSpan.Start) .Parent?.AncestorsAndSelf() - .OfType() - .First(); + .OfType() + .FirstOrDefault(member => member is MethodDeclarationSyntax or PropertyDeclarationSyntax); - if(methodDeclaration == null) + if(memberDeclaration == null) return; context.RegisterCodeFix( CodeAction.Create( title: "Use inline expression body for switch expression", - createChangedDocument: c => UseInlineExpressionBodyAsync(context.Document, methodDeclaration, c), + createChangedDocument: c => UseInlineExpressionBodyAsync(context.Document, memberDeclaration, c), equivalenceKey: nameof(SwitchExpressionMethodCodeFixProvider)), diagnostic); } - private static async Task UseInlineExpressionBodyAsync(Document document, MethodDeclarationSyntax methodDecl, CancellationToken cancellationToken) + private static async Task UseInlineExpressionBodyAsync(Document document, MemberDeclarationSyntax memberDecl, CancellationToken cancellationToken) { - var sourceText = await document.GetTextAsync(cancellationToken); - var parameterText = methodDecl.ParameterList.ToString(); - var methodStartLine = sourceText.Lines.GetLineFromPosition(methodDecl.SpanStart); - - SwitchExpressionSyntax? switchExpr = null; - ExpressionSyntax? governingExpression = null; - var switchBodyText = string.Empty; - - if (methodDecl.Body != null) - { - // Case: Block-Body with a Return-Statement that contains a Switch-Expression - var returnStmt = (ReturnStatementSyntax)methodDecl.Body.Statements[0]; - if (returnStmt.Expression is not SwitchExpressionSyntax matchingSwitchExpr) - return document; - - switchExpr = matchingSwitchExpr; - governingExpression = switchExpr.GoverningExpression; - - // Extract the switch body text: - var switchStart = switchExpr.SwitchKeyword.SpanStart; - var switchEnd = switchExpr.CloseBraceToken.Span.End; - switchBodyText = sourceText.ToString(TextSpan.FromBounds(switchStart, switchEnd)); - } - else if (methodDecl.ExpressionBody != null) - { - // Case 2: Expression-Body with a poorly formatted Switch-Expression - switchExpr = (SwitchExpressionSyntax)methodDecl.ExpressionBody.Expression; - governingExpression = switchExpr.GoverningExpression; - - // Extract the switch body text: - var switchStart = switchExpr.SwitchKeyword.SpanStart; - var switchEnd = switchExpr.CloseBraceToken.Span.End; - switchBodyText = sourceText.ToString(TextSpan.FromBounds(switchStart, switchEnd)); - } - - if (switchExpr is null || governingExpression is null) + var switchExpr = SwitchExpressionOf(memberDecl); + var headerEnd = HeaderEndOf(memberDecl); + if (switchExpr is null || headerEnd is null) return document; + var sourceText = await document.GetTextAsync(cancellationToken); + var memberStartLine = sourceText.Lines.GetLineFromPosition(memberDecl.SpanStart); + + // + // Everything in front of the body stays as it was written: the attributes, the modifiers, the type, + // the name, and of a method its type parameters, parameters, and constraints. Building it anew from + // some of these parts loses the others. + // + var headerText = sourceText.ToString(TextSpan.FromBounds(memberDecl.SpanStart, headerEnd.Value)).TrimEnd(); + // Extract the governing expression and the switch body: - var govExprText = sourceText.ToString(governingExpression.Span); + var govExprText = sourceText.ToString(switchExpr.GoverningExpression.Span); + var switchBodyText = sourceText.ToString(TextSpan.FromBounds(switchExpr.OpenBraceToken.SpanStart, switchExpr.CloseBraceToken.Span.End)); - // Create the new method with inline expression body and correct formatting: - var returnTypeText = methodDecl.ReturnType.ToString(); - var modifiersText = string.Join(" ", methodDecl.Modifiers); - var methodNameText = methodDecl.Identifier.Text; - - // Determine the indentation of the method: - var methodIndentation = ""; - for (var i = methodStartLine.Start; i < methodDecl.SpanStart; i++) + // Determine the indentation of the member: + var memberIndentation = ""; + for (var i = memberStartLine.Start; i < memberDecl.SpanStart; i++) { if (char.IsWhiteSpace(sourceText[i])) - methodIndentation += sourceText[i]; + memberIndentation += sourceText[i]; else break; } - // Erstelle die neue Methode mit Expression-Body und korrekter Formatierung - var newMethodText = new StringBuilder(); - newMethodText.Append($"{modifiersText} {returnTypeText} {methodNameText}{parameterText} => {govExprText} switch"); + // Create the new member with an expression body and the switch keyword on the same line: + var newMemberText = new StringBuilder(); + newMemberText.Append($"{headerText} => {govExprText} switch"); - // Formatiere die geschweiften Klammern und den Switch-Body - var switchBody = switchBodyText.Substring("switch".Length).Trim(); + // The switch cases are indented by four spaces more than the member: + var caseIndentation = memberIndentation + " "; + newMemberText.Append(FormatSwitchBody(switchBodyText, memberIndentation, caseIndentation)); - // Bestimme die Einrückung für die Switch-Cases (4 Spaces oder 1 Tab mehr als die Methode) - var caseIndentation = methodIndentation + " "; // 4 Spaces Einrückung - - // Verarbeite die Klammern und formatiere den Body - var formattedSwitchBody = FormatSwitchBody(switchBody, methodIndentation, caseIndentation); - newMethodText.Append(formattedSwitchBody); - - // Ersetze die alte Methoden-Deklaration mit dem neuen Text - var newText = sourceText.Replace(methodDecl.Span, newMethodText.ToString()); + // Replace the old declaration with the new text: + var newText = sourceText.Replace(memberDecl.Span, newMemberText.ToString()); return document.WithText(newText); } - private static string FormatSwitchBody(string switchBody, string methodIndentation, string caseIndentation) + private static SwitchExpressionSyntax? SwitchExpressionOf(MemberDeclarationSyntax memberDecl) => memberDecl switch + { + MethodDeclarationSyntax methodDecl => SwitchExpressionOf(methodDecl.Body, methodDecl.ExpressionBody), + PropertyDeclarationSyntax { ExpressionBody: not null } propertyDecl => SwitchExpressionOf(null, propertyDecl.ExpressionBody), + PropertyDeclarationSyntax { AccessorList.Accessors.Count: 1 } propertyDecl => SwitchExpressionOf(propertyDecl.AccessorList.Accessors[0].Body, propertyDecl.AccessorList.Accessors[0].ExpressionBody), + + _ => null, + }; + + private static SwitchExpressionSyntax? SwitchExpressionOf(BlockSyntax? body, ArrowExpressionClauseSyntax? expressionBody) + { + if (expressionBody?.Expression is SwitchExpressionSyntax inlineSwitchExpr) + return inlineSwitchExpr; + + // A block body with a return statement that contains a switch expression: + if (body is { Statements.Count: 1 } && body.Statements[0] is ReturnStatementSyntax { Expression: SwitchExpressionSyntax returnedSwitchExpr }) + return returnedSwitchExpr; + + return null; + } + + private static int? HeaderEndOf(MemberDeclarationSyntax memberDecl) => memberDecl switch + { + MethodDeclarationSyntax { ConstraintClauses.Count: > 0 } methodDecl => methodDecl.ConstraintClauses.Last().Span.End, + MethodDeclarationSyntax methodDecl => methodDecl.ParameterList.Span.End, + PropertyDeclarationSyntax propertyDecl => propertyDecl.Identifier.Span.End, + + _ => null, + }; + + private static string FormatSwitchBody(string switchBody, string memberIndentation, string caseIndentation) { var result = new StringBuilder(); @@ -136,7 +133,7 @@ public class SwitchExpressionMethodCodeFixProvider : CodeFixProvider // Add braces with correct indentation: result.AppendLine(); - result.Append($"{methodIndentation}{{"); + result.Append($"{memberIndentation}{{"); // Process each line of the switch body: var lines = bodyWithoutBraces.Split(["\r\n", "\n"], System.StringSplitOptions.None); @@ -155,7 +152,7 @@ public class SwitchExpressionMethodCodeFixProvider : CodeFixProvider // Add the closing brace with correct indentation: result.AppendLine(); - result.Append($"{methodIndentation}}};"); + result.Append($"{memberIndentation}}};"); return result.ToString(); } diff --git a/app/Tests/Analyzers/SwitchExpressionMethodAnalyzerTests.cs b/app/Tests/Analyzers/SwitchExpressionMethodAnalyzerTests.cs new file mode 100644 index 000000000..5a85ed9db --- /dev/null +++ b/app/Tests/Analyzers/SwitchExpressionMethodAnalyzerTests.cs @@ -0,0 +1,192 @@ +using AIStudio.Tests.Models.Generation; + +using SourceCodeRules.StyleAnalyzers; +using SourceCodeRules.StyleCodeFixes; + +namespace AIStudio.Tests.Analyzers; + +/// +/// Checks that methods and properties which only return a switch expression start it on the line of their arrow, +/// and that the code fix of MWAIS0006 keeps everything else of the member. +/// +/// +/// Extension blocks turn many such methods into properties, so the rule has to know properties as well: a +/// getter which does nothing but return a switch expression reads like the method it replaced. +/// +[TestFixture] +public sealed class SwitchExpressionMethodAnalyzerTests +{ + private const string SWITCH = "this.Kind switch { Kind.CALL => \"Call\", _ => \"Meeting\" }"; + + [TestCase("public string Label() { return " + SWITCH + "; }", "Method", TestName = "A method which returns a switch expression from a block")] + [TestCase("public string Label() =>\n" + SWITCH + ";", "Method", TestName = "A method whose switch expression starts on the next line")] + [TestCase("public string Label =>\n" + SWITCH + ";", "Property", TestName = "A property whose switch expression starts on the next line")] + [TestCase("public string Label { get { return " + SWITCH + "; } }", "Property", TestName = "A getter which returns a switch expression from a block")] + [TestCase("public string Label { get => " + SWITCH + "; }", "Property", TestName = "A getter with a switch expression as its body")] + public async Task AMemberOfAClassIsRefused(string member, string kind) + { + var reported = await CompilationHarness.AnalyzeAsync(ClassWith(member), new SwitchExpressionMethodAnalyzer()); + + using (Assert.EnterMultipleScope()) + { + Assert.That(reported, Has.Count.EqualTo(1)); + Assert.That(reported.FirstOrDefault()?.Id, Is.EqualTo("MWAIS0006")); + Assert.That(reported.FirstOrDefault()?.GetMessage(), Does.StartWith($"{kind} with a switch expression")); + } + } + + [TestCase("public string Label =>\nkind switch { Kind.CALL => \"Call\", _ => \"Meeting\" };", TestName = "An extension property whose switch expression starts on the next line")] + [TestCase("public string Label { get { return kind switch { Kind.CALL => \"Call\", _ => \"Meeting\" }; } }", TestName = "The getter of an extension property which returns a switch expression from a block")] + [TestCase("public string Label() { return kind switch { Kind.CALL => \"Call\", _ => \"Meeting\" }; }", TestName = "An extension method which returns a switch expression from a block")] + public async Task AMemberOfAnExtensionBlockIsRefused(string member) + { + var reported = await CompilationHarness.AnalyzeAsync(ExtensionBlockWith(member), new SwitchExpressionMethodAnalyzer()); + + using (Assert.EnterMultipleScope()) + { + Assert.That(reported, Has.Count.EqualTo(1)); + Assert.That(reported.FirstOrDefault()?.Id, Is.EqualTo("MWAIS0006")); + } + } + + [TestCase("public string Label() => " + SWITCH + ";", TestName = "A method with the switch expression on the line of its arrow")] + [TestCase("public string Label => " + SWITCH + ";", TestName = "A property with the switch expression on the line of its arrow")] + [TestCase("public string Label { get { return " + SWITCH + "; } set { } }", TestName = "A property with a getter and a setter")] + [TestCase("public string Label { get { var kind = this.Kind; return kind switch { Kind.CALL => \"Call\", _ => \"Meeting\" }; } }", TestName = "A getter which does more than return a switch expression")] + [TestCase("public string Label() { return \"Meeting\"; }", TestName = "A method which returns no switch expression")] + public async Task AnythingElseIsLeftAlone(string member) + { + var reported = await CompilationHarness.AnalyzeAsync(ClassWith(member), new SwitchExpressionMethodAnalyzer()); + + Assert.That(reported, Is.Empty); + } + + [Test] + public async Task TheCodeFixKeepsTheAttributesTypeParametersAndConstraintsOfAMethod() + { + var source = ClassWith( + """ + /// Names the hash of a value. + [System.Diagnostics.Contracts.Pure] + public static string Label(T value) where T : struct + { + return value.GetHashCode() switch + { + 0 => "Zero", + _ => "Other", + }; + } + """); + + var expected = ClassWith( + """ + /// Names the hash of a value. + [System.Diagnostics.Contracts.Pure] + public static string Label(T value) where T : struct => value.GetHashCode() switch + { + 0 => "Zero", + _ => "Other", + }; + """); + + var fixedSource = await CompilationHarness.FixAsync(source, new SwitchExpressionMethodAnalyzer(), new SwitchExpressionMethodCodeFixProvider()); + + Assert.That(fixedSource.ReplaceLineEndings("\n"), Is.EqualTo(expected.ReplaceLineEndings("\n"))); + } + + [Test] + public async Task TheCodeFixTurnsAGetterIntoAnExpressionBody() + { + var source = ClassWith( + """ + public string Label + { + get + { + return this.Kind switch + { + Kind.CALL => "Call", + _ => "Meeting", + }; + } + } + """); + + var expected = ClassWith( + """ + public string Label => this.Kind switch + { + Kind.CALL => "Call", + _ => "Meeting", + }; + """); + + var fixedSource = await CompilationHarness.FixAsync(source, new SwitchExpressionMethodAnalyzer(), new SwitchExpressionMethodCodeFixProvider()); + + Assert.That(fixedSource.ReplaceLineEndings("\n"), Is.EqualTo(expected.ReplaceLineEndings("\n"))); + } + + [Test] + public async Task TheCodeFixMovesTheSwitchOfAnExtensionPropertyOntoTheLineOfItsArrow() + { + var source = ExtensionBlockWith( + """ + public string Label => + kind switch + { + Kind.CALL => "Call", + _ => "Meeting", + }; + """); + + var expected = ExtensionBlockWith( + """ + public string Label => kind switch + { + Kind.CALL => "Call", + _ => "Meeting", + }; + """); + + var fixedSource = await CompilationHarness.FixAsync(source, new SwitchExpressionMethodAnalyzer(), new SwitchExpressionMethodCodeFixProvider()); + + Assert.That(fixedSource.ReplaceLineEndings("\n"), Is.EqualTo(expected.ReplaceLineEndings("\n"))); + } + + private static string ClassWith(string members) => + $$""" + namespace Sample; + + public enum Kind + { + CALL, + MEETING, + } + + public sealed class Meeting + { + public Kind Kind { get; set; } = Kind.MEETING; + + {{members}} + } + """; + + private static string ExtensionBlockWith(string members) => + $$""" + namespace Sample; + + public enum Kind + { + CALL, + MEETING, + } + + public static class KindExtensions + { + extension(Kind kind) + { + {{members}} + } + } + """; +} diff --git a/app/Tests/Assistants/SendToReceiverTests.cs b/app/Tests/Assistants/SendToReceiverTests.cs index 41a591006..86c7a2ff7 100644 --- a/app/Tests/Assistants/SendToReceiverTests.cs +++ b/app/Tests/Assistants/SendToReceiverTests.cs @@ -25,7 +25,7 @@ public sealed class SendToReceiverTests private static readonly Assembly APP = typeof(AssistantLaunchService).Assembly; private static IEnumerable Destinations() => Enum.GetValues() - .Where(component => component.AllowSendTo()) + .Where(component => component.AllowSendTo) .Where(component => component is not AIStudio.Tools.Components.CHAT); [TestCaseSource(nameof(Destinations))] diff --git a/app/Tests/Models/Generation/CompilationHarness.cs b/app/Tests/Models/Generation/CompilationHarness.cs index 725ee7be8..aa5adbf05 100644 --- a/app/Tests/Models/Generation/CompilationHarness.cs +++ b/app/Tests/Models/Generation/CompilationHarness.cs @@ -1,6 +1,9 @@ using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Text; namespace AIStudio.Tests.Models.Generation; @@ -70,6 +73,53 @@ public static class CompilationHarness return reported; } + /// + /// Runs one analyzer over a snippet and applies its code fix to the first diagnostic it reports. + /// + /// + /// The code fix runs in a workspace of its own, as it does in the IDE. The fixed source still has to + /// compile, since a code fix which breaks the code is worse than none. + /// + /// The C# source to fix. + /// The analyzer which reports what to fix. + /// The code fix to apply. + /// The fixed source. + public static async Task FixAsync(string source, DiagnosticAnalyzer analyzer, CodeFixProvider codeFix) + { + using var workspace = new AdhocWorkspace(); + var projectInfo = ProjectInfo.Create( + ProjectId.CreateNewId(), + VersionStamp.Default, + "SnippetUnderTest", + "SnippetUnderTest", + LanguageNames.CSharp, + compilationOptions: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, nullableContextOptions: NullableContextOptions.Enable), + parseOptions: new CSharpParseOptions(LanguageVersion.Latest), + metadataReferences: REFERENCES.Value); + + var project = workspace.AddProject(projectInfo); + var document = workspace.AddDocument(project.Id, "Snippet.cs", SourceText.From(source)); + + var compilation = await document.Project.GetCompilationAsync(); + Assert.That(ErrorsOf(compilation!), Is.Empty, "The snippet has to compile, or the code fix is being asked about code which does not exist."); + + var reported = await compilation!.WithAnalyzers([analyzer]).GetAnalyzerDiagnosticsAsync(); + Assert.That(reported, Is.Not.Empty, "The analyzer has to report something, or there is nothing for the code fix to do."); + + var actions = new List(); + var context = new CodeFixContext(document, reported[0], (action, _) => actions.Add(action), CancellationToken.None); + await codeFix.RegisterCodeFixesAsync(context); + Assert.That(actions, Has.Count.EqualTo(1), "The code fix has to offer exactly one action."); + + var operations = await actions[0].GetOperationsAsync(CancellationToken.None); + var changedSolution = operations.OfType().Single().ChangedSolution; + var fixedText = await changedSolution.GetDocument(document.Id)!.GetTextAsync(); + var fixedSource = fixedText.ToString(); + + Assert.That(ErrorsOf(Compile(fixedSource)), Is.Empty, "The fixed source has to compile."); + return fixedSource; + } + private static MetadataReference[] GatherReferences() { // diff --git a/app/Tests/Provider/ImageSizeLimitTests.cs b/app/Tests/Provider/ImageSizeLimitTests.cs index c81c40b57..5cdcea3c6 100644 --- a/app/Tests/Provider/ImageSizeLimitTests.cs +++ b/app/Tests/Provider/ImageSizeLimitTests.cs @@ -19,7 +19,7 @@ public sealed class ImageSizeLimitTests { using (Assert.EnterMultipleScope()) { - Assert.That(LLMProviders.ANTHROPIC.GetMaxImageSizeBytes(), Is.EqualTo(3_932_160)); + Assert.That(LLMProviders.ANTHROPIC.MaxImageSizeBytes, Is.EqualTo(3_932_160)); Assert.That(IImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.ANTHROPIC)), Is.EqualTo(3_932_160)); } } @@ -29,7 +29,7 @@ public sealed class ImageSizeLimitTests { using (Assert.EnterMultipleScope()) { - Assert.That(LLMProviders.OPEN_AI.GetMaxImageSizeBytes(), Is.Null, "Nobody stated a limit, and no number stands in for that."); + Assert.That(LLMProviders.OPEN_AI.MaxImageSizeBytes, Is.Null, "Nobody stated a limit, and no number stands in for that."); Assert.That(IImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.OPEN_AI)), Is.EqualTo(IImageSourceExtensions.MAX_IMAGE_SIZE_BYTES)); } } @@ -39,7 +39,7 @@ public sealed class ImageSizeLimitTests { using (Assert.EnterMultipleScope()) { - Assert.That(Host.LLMMAN.GetMaxImageSizeBytes(), Is.EqualTo(1_048_576)); + Assert.That(Host.LLMMAN.MaxImageSizeBytes, Is.EqualTo(1_048_576)); Assert.That(IImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.SELF_HOSTED, Host.LLMMAN)), Is.EqualTo(1_048_576)); Assert.That(IImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.SELF_HOSTED, Host.OLLAMA)), Is.EqualTo(IImageSourceExtensions.MAX_IMAGE_SIZE_BYTES), "Ollama states no limit we know of."); } diff --git a/app/Tests/Provider/OpenAI/SystemPromptRoleTests.cs b/app/Tests/Provider/OpenAI/SystemPromptRoleTests.cs index 06c5b0bab..a6a3d7aca 100644 --- a/app/Tests/Provider/OpenAI/SystemPromptRoleTests.cs +++ b/app/Tests/Provider/OpenAI/SystemPromptRoleTests.cs @@ -33,7 +33,7 @@ public sealed class SystemPromptRoleTests { var profile = LLMProviders.OPEN_AI.GetModelProfile(new Model(modelId, null)); - Assert.That(profile.SystemPromptRole.ToOpenAIRole(), Is.EqualTo(role)); + Assert.That(profile.SystemPromptRole.OpenAIRole, Is.EqualTo(role)); } [Test] @@ -43,6 +43,6 @@ public sealed class SystemPromptRoleTests // A model the rules do not know is almost always a new one, and the older generations which // still want "system" say so in their families. // - Assert.That(SystemPromptRole.UNKNOWN.ToOpenAIRole(), Is.EqualTo("developer")); + Assert.That(SystemPromptRole.UNKNOWN.OpenAIRole, Is.EqualTo("developer")); } } \ No newline at end of file diff --git a/app/Tests/Provider/SelfHosted/HostExtensionsTests.cs b/app/Tests/Provider/SelfHosted/HostExtensionsTests.cs index 04a256972..fd721d090 100644 --- a/app/Tests/Provider/SelfHosted/HostExtensionsTests.cs +++ b/app/Tests/Provider/SelfHosted/HostExtensionsTests.cs @@ -21,7 +21,7 @@ public sealed class HostExtensionsTests [TestCaseSource(nameof(ALL_HOSTS))] public void TheDialogsOfferToLoadModelsExactlyWhereTheEngineCanListThem(Host host) { - Assert.That(LLMProviders.SELF_HOSTED.CanLoadModels(host, null), Is.EqualTo(host.IsModelListSupported())); + Assert.That(LLMProviders.SELF_HOSTED.CanLoadModels(host, null), Is.EqualTo(host.IsModelListSupported)); } [Test] @@ -30,7 +30,7 @@ public sealed class HostExtensionsTests // // There is no fixed chat model to offer instead, so such an engine would offer an empty list: // - var unlisted = ALL_HOSTS.Where(host => host is not Host.NONE && host.IsChatSupported() && !host.IsModelListSupported()); + var unlisted = ALL_HOSTS.Where(host => host is not Host.NONE && host.IsChatSupported && !host.IsModelListSupported); Assert.That(unlisted, Is.Empty); } @@ -40,7 +40,7 @@ public sealed class HostExtensionsTests // // There is no fixed embedding model to offer instead, so such an engine would offer an empty list: // - var unlisted = ALL_HOSTS.Where(host => host.IsEmbeddingSupported() && !host.IsModelListSupported()); + var unlisted = ALL_HOSTS.Where(host => host.IsEmbeddingSupported && !host.IsModelListSupported); Assert.That(unlisted, Is.Empty); } @@ -51,7 +51,7 @@ public sealed class HostExtensionsTests // The provider offers the one model of whisper.cpp under a fixed name. Any other engine // which transcribes but cannot list its models would offer an empty list: // - var unlisted = ALL_HOSTS.Where(host => host.IsTranscriptionSupported() && !host.IsModelListSupported()); + var unlisted = ALL_HOSTS.Where(host => host.IsTranscriptionSupported && !host.IsModelListSupported); Assert.That(unlisted, Is.EqualTo(new[] { Host.WHISPER_CPP })); } @@ -60,9 +60,9 @@ public sealed class HostExtensionsTests { using (Assert.EnterMultipleScope()) { - Assert.That(Host.NONE.IsModelListSupported(), Is.False); - Assert.That(Host.NONE.IsEmbeddingSupported(), Is.False); - Assert.That(Host.NONE.IsTranscriptionSupported(), Is.False); + Assert.That(Host.NONE.IsModelListSupported, Is.False); + Assert.That(Host.NONE.IsEmbeddingSupported, Is.False); + Assert.That(Host.NONE.IsTranscriptionSupported, Is.False); Assert.That(LLMProviders.SELF_HOSTED.CanLoadModels(Host.NONE, "a key"), Is.False); } } diff --git a/app/Tests/Settings/EnumNamesTests.cs b/app/Tests/Settings/EnumNamesTests.cs index 157032c30..f30948dd1 100644 --- a/app/Tests/Settings/EnumNamesTests.cs +++ b/app/Tests/Settings/EnumNamesTests.cs @@ -20,7 +20,7 @@ public sealed class EnumNamesTests [TestCase(" Every_Message ")] public void ANameCountsWhateverItsCase(string text) { - Assert.That(EnumNames.TryParse(text, out var mode), Is.True); + Assert.That(DataSourceRetrievalMode.TryParseName(text, out var mode), Is.True); Assert.That(mode, Is.EqualTo(DataSourceRetrievalMode.EVERY_MESSAGE)); } @@ -29,7 +29,7 @@ public sealed class EnumNamesTests [TestCase("0x1")] public void ANumberDoesNotCountEvenWhenAMemberHasIt(string text) { - Assert.That(EnumNames.TryParse(text, out _), Is.False, "Enum.TryParse would read 1 as EVERY_MESSAGE."); + Assert.That(DataSourceRetrievalMode.TryParseName(text, out _), Is.False, "Enum.TryParse would read 1 as EVERY_MESSAGE."); } [Test] @@ -37,8 +37,8 @@ public sealed class EnumNamesTests { using (Assert.EnterMultipleScope()) { - Assert.That(EnumNames.TryParse("SEMANTIC_SEARCH, EVERY_MESSAGE", out _), Is.False, "Enum.TryParse would combine them to EVERY_MESSAGE."); - Assert.That(EnumNames.TryParse("HIGH, MEDIUM", out _), Is.False, "Enum.TryParse would combine them to a confidence level above HIGH."); + Assert.That(DataSourceRetrievalMode.TryParseName("SEMANTIC_SEARCH, EVERY_MESSAGE", out _), Is.False, "Enum.TryParse would combine them to EVERY_MESSAGE."); + Assert.That(ConfidenceLevel.TryParseName("HIGH, MEDIUM", out _), Is.False, "Enum.TryParse would combine them to a confidence level above HIGH."); } } @@ -48,7 +48,7 @@ public sealed class EnumNamesTests [TestCase("EVERY MESSAGE")] public void NoNameDoesNotCount(string? text) { - Assert.That(EnumNames.TryParse(text, out var mode), Is.False); + Assert.That(DataSourceRetrievalMode.TryParseName(text, out var mode), Is.False); Assert.That(mode, Is.EqualTo(default(DataSourceRetrievalMode))); } diff --git a/app/Tests/Settings/TranscriptionOpusBitrateTests.cs b/app/Tests/Settings/TranscriptionOpusBitrateTests.cs index 33a756824..00691fecd 100644 --- a/app/Tests/Settings/TranscriptionOpusBitrateTests.cs +++ b/app/Tests/Settings/TranscriptionOpusBitrateTests.cs @@ -29,7 +29,7 @@ public sealed class TranscriptionOpusBitrateTests foreach (var bitrate in Enum.GetValues()) { Assert.That(EXPECTED_BITS_PER_SECOND.ContainsKey(bitrate), Is.True, $"The selection offers {bitrate}, so this test has to state what that is worth in bits per second."); - Assert.That(bitrate.GetBitsPerSecond(), Is.EqualTo(EXPECTED_BITS_PER_SECOND[bitrate]), $"{bitrate} is what the user picked; anything else travels to the encoder behind their back."); + Assert.That(bitrate.BitsPerSecond, Is.EqualTo(EXPECTED_BITS_PER_SECOND[bitrate]), $"{bitrate} is what the user picked; anything else travels to the encoder behind their back."); } } @@ -39,7 +39,7 @@ public sealed class TranscriptionOpusBitrateTests var undeclared = (TranscriptionOpusBitrate)999; Assert.That(Enum.IsDefined(undeclared), Is.False, "The point of this test is a value outside the enum; a declared one would prove nothing."); - Assert.That(undeclared.GetBitsPerSecond(), Is.EqualTo(128_000u), "Not knowing which quality was meant is no reason to pick the worst one available."); + Assert.That(undeclared.BitsPerSecond, Is.EqualTo(128_000u), "Not knowing which quality was meant is no reason to pick the worst one available."); } [Test] diff --git a/app/Tests/Tools/AppAccess/WebRootFilesTests.cs b/app/Tests/Tools/AppAccess/WebRootFilesTests.cs index 3712d3081..bd2063790 100644 --- a/app/Tests/Tools/AppAccess/WebRootFilesTests.cs +++ b/app/Tests/Tools/AppAccess/WebRootFilesTests.cs @@ -24,7 +24,7 @@ public sealed class WebRootFilesTests { private static IEnumerable ChangelogFiles() => Changelog.LOGS.Select(log => log.Filename); - private static IEnumerable SpecificationVersions() => Enum.GetValues().Where(version => version.WasSpecificationSelected()); + private static IEnumerable SpecificationVersions() => Enum.GetValues().Where(version => version.WasSpecificationSelected); private static string ReadAppPageSource([CallerFilePath] string sourceFilePath = "") => File.ReadAllText(Path.Combine(Path.GetDirectoryName(sourceFilePath)!, "..", "..", "..", "MindWork AI Studio", "App.razor")); @@ -78,7 +78,7 @@ public sealed class WebRootFilesTests var destinationPath = Path.Combine(Path.GetTempPath(), $"eri-specification-{Guid.NewGuid():N}.json"); try { - Assert.That(await webRootFiles.CopyToAsync(version.SpecificationURL(), destinationPath), Is.True); + Assert.That(await webRootFiles.CopyToAsync(version.SpecificationURL, destinationPath), Is.True); Assert.That(await File.ReadAllTextAsync(destinationPath), Is.EqualTo(await version.ReadSpecification(webRootFiles))); } finally diff --git a/app/Tests/Tools/AssistantLaunch/AssistantLaunchServiceTests.cs b/app/Tests/Tools/AssistantLaunch/AssistantLaunchServiceTests.cs index ed18e8d29..5bcc864ad 100644 --- a/app/Tests/Tools/AssistantLaunch/AssistantLaunchServiceTests.cs +++ b/app/Tests/Tools/AssistantLaunch/AssistantLaunchServiceTests.cs @@ -42,7 +42,7 @@ public sealed class AssistantLaunchServiceTests using (Assert.EnterMultipleScope()) { Assert.That(destinations, Is.Not.Empty); - Assert.That(destinations.All(destination => destination.AllowSendTo()), Is.True); + Assert.That(destinations.All(destination => destination.AllowSendTo), Is.True); Assert.That(destinations, Does.Not.Contain(AIStudio.Tools.Components.DYNAMIC_ASSISTANT), "Assistant plugins cannot take content yet."); Assert.That(destinations, Does.Not.Contain(AIStudio.Tools.Components.NONE)); } @@ -58,7 +58,7 @@ public sealed class AssistantLaunchServiceTests [Test] public void ShorterNamesComeFirst() { - var lengths = AssistantLaunchService.SelectDestinations(AIStudio.Tools.Components.CHAT, _ => true).Select(destination => destination.Name().Length).ToList(); + var lengths = AssistantLaunchService.SelectDestinations(AIStudio.Tools.Components.CHAT, _ => true).Select(destination => destination.Name.Length).ToList(); Assert.That(lengths, Is.Ordered); } } diff --git a/app/Tests/Tools/CodeHighlighting/CodeLanguageDetectorTests.cs b/app/Tests/Tools/CodeHighlighting/CodeLanguageDetectorTests.cs index 5d2b22a54..db1fe28aa 100644 --- a/app/Tests/Tools/CodeHighlighting/CodeLanguageDetectorTests.cs +++ b/app/Tests/Tools/CodeHighlighting/CodeLanguageDetectorTests.cs @@ -77,7 +77,7 @@ public sealed class CodeLanguageDetectorTests { using (Assert.EnterMultipleScope()) { - var isFormat = FileExportFormatExtensions.TryFromCodeFenceLanguage(fenceLanguage, out _); + var isFormat = FileExportFormat.TryFromCodeFenceLanguage(fenceLanguage, out _); Assert.That(isFormat || SourceCodeLanguages.Aliases.Contains(fenceLanguage, StringComparer.OrdinalIgnoreCase), Is.True, "The export would save it as a text file."); Assert.That(CodeHighlighters.TryGetRules(fenceLanguage, out _) || LIBRARY_LANGUAGES.Contains(fenceLanguage), Is.True, "Nobody highlights it."); } diff --git a/app/Tests/Tools/CodeHighlighting/CodeTokenKindExtensionsTests.cs b/app/Tests/Tools/CodeHighlighting/CodeTokenKindExtensionsTests.cs index 3b14d8daf..e638790f8 100644 --- a/app/Tests/Tools/CodeHighlighting/CodeTokenKindExtensionsTests.cs +++ b/app/Tests/Tools/CodeHighlighting/CodeTokenKindExtensionsTests.cs @@ -14,7 +14,7 @@ public sealed class CodeTokenKindExtensionsTests public async Task EveryKindHasAClassWhichTheStyleSheetColors([Values] CodeTokenKind kind) { var styleSheet = await new WebRootFiles().ReadTextAsync("system/MudBlazor.Markdown/MudBlazor.Markdown.min.css"); - var cssClass = kind.ToCssClass().Split(' ')[0]; + var cssClass = kind.CssClass.Split(' ')[0]; Assert.That(styleSheet, Does.Contain($".{cssClass}"), "A library which renames its classes would leave this kind without color."); } diff --git a/app/Tests/Tools/FileExportFormatTests.cs b/app/Tests/Tools/FileExportFormatTests.cs index fc6ae645f..307f8a01f 100644 --- a/app/Tests/Tools/FileExportFormatTests.cs +++ b/app/Tests/Tools/FileExportFormatTests.cs @@ -13,11 +13,11 @@ public sealed class FileExportFormatTests { using (Assert.EnterMultipleScope()) { - Assert.That(FileExportFormat.MICROSOFT_WORD.FollowsPageAnchors(), Is.False, "Word looks for a file whose name ends in the fragment, finds none, and refuses the link."); - Assert.That(FileExportFormat.OPEN_DOCUMENT_TEXT.FollowsPageAnchors(), Is.False, "LibreOffice does the same, verified on 2026-09-15 with an exported .odt."); - Assert.That(FileExportFormat.HTML.FollowsPageAnchors(), Is.True, "A browser opens the document on the page the fragment names."); - Assert.That(FileExportFormat.MARKDOWN.FollowsPageAnchors(), Is.True); - Assert.That(FileExportFormat.LATEX.FollowsPageAnchors(), Is.True); + Assert.That(FileExportFormat.MICROSOFT_WORD.FollowsPageAnchors, Is.False, "Word looks for a file whose name ends in the fragment, finds none, and refuses the link."); + Assert.That(FileExportFormat.OPEN_DOCUMENT_TEXT.FollowsPageAnchors, Is.False, "LibreOffice does the same, verified on 2026-09-15 with an exported .odt."); + Assert.That(FileExportFormat.HTML.FollowsPageAnchors, Is.True, "A browser opens the document on the page the fragment names."); + Assert.That(FileExportFormat.MARKDOWN.FollowsPageAnchors, Is.True); + Assert.That(FileExportFormat.LATEX.FollowsPageAnchors, Is.True); } } @@ -27,7 +27,7 @@ public sealed class FileExportFormatTests // Whoever adds a format decides what its reader can follow, rather than inheriting an // assumption. This fails for a format which nobody thought about, because the list below // has to name it: - Assert.That(FileExportFormatExtensions.ANSWER_FORMATS, Is.EquivalentTo(new[] + Assert.That(FileExportFormat.AnswerFormats, Is.EquivalentTo(new[] { FileExportFormat.MICROSOFT_WORD, FileExportFormat.OPEN_DOCUMENT_TEXT, @@ -59,10 +59,10 @@ public sealed class FileExportFormatTests { using (Assert.EnterMultipleScope()) { - Assert.That(FileExportFormat.HTML.NeedsPageTitle(), Is.True, "Without one, the browser tab shows the random name of the temporary file Pandoc read."); - Assert.That(FileExportFormat.MICROSOFT_WORD.NeedsPageTitle(), Is.False, "Word would keep it as a document property nobody asked for."); - Assert.That(FileExportFormat.OPEN_DOCUMENT_TEXT.NeedsPageTitle(), Is.False, "The same goes for an OpenDocument file."); - Assert.That(FileExportFormat.LATEX.NeedsPageTitle(), Is.False); + Assert.That(FileExportFormat.HTML.NeedsPageTitle, Is.True, "Without one, the browser tab shows the random name of the temporary file Pandoc read."); + Assert.That(FileExportFormat.MICROSOFT_WORD.NeedsPageTitle, Is.False, "Word would keep it as a document property nobody asked for."); + Assert.That(FileExportFormat.OPEN_DOCUMENT_TEXT.NeedsPageTitle, Is.False, "The same goes for an OpenDocument file."); + Assert.That(FileExportFormat.LATEX.NeedsPageTitle, Is.False); } } @@ -81,9 +81,9 @@ public sealed class FileExportFormatTests { using (Assert.EnterMultipleScope()) { - Assert.That(FileExportFormatExtensions.TryFromCodeFenceLanguage(language, out var format), Is.True); + Assert.That(FileExportFormat.TryFromCodeFenceLanguage(language, out var format), Is.True); Assert.That(format, Is.EqualTo(expectedFormat)); - Assert.That(format.IsPlainText(), Is.True, "A code block holds text, so the export writes it as it is."); + Assert.That(format.IsPlainText, Is.True, "A code block holds text, so the export writes it as it is."); } } @@ -92,16 +92,16 @@ public sealed class FileExportFormatTests { using (Assert.EnterMultipleScope()) { - Assert.That(FileExportFormat.MICROSOFT_WORD.IsPlainText(), Is.False, "A Word file is an archive, and writing text into one breaks it."); - Assert.That(FileExportFormat.OPEN_DOCUMENT_TEXT.IsPlainText(), Is.False); - Assert.That(FileExportFormat.NONE.IsPlainText(), Is.False, "No format means no file."); - Assert.That(FileExportFormat.UNKNOWN.IsPlainText(), Is.False); - Assert.That(FileExportFormat.HTML.IsPlainText(), Is.True, "A page the model wrote is a finished file, even though an entire answer needs Pandoc to become one."); - Assert.That(FileExportFormat.LATEX.IsPlainText(), Is.True); - Assert.That(FileExportFormat.MARKDOWN.IsPlainText(), Is.True); - Assert.That(FileExportFormat.CSV.IsPlainText(), Is.True); - Assert.That(FileExportFormat.TSV.IsPlainText(), Is.True); - Assert.That(FileExportFormat.SOURCE_CODE.IsPlainText(), Is.True, "Code is text, whatever its language."); + Assert.That(FileExportFormat.MICROSOFT_WORD.IsPlainText, Is.False, "A Word file is an archive, and writing text into one breaks it."); + Assert.That(FileExportFormat.OPEN_DOCUMENT_TEXT.IsPlainText, Is.False); + Assert.That(FileExportFormat.NONE.IsPlainText, Is.False, "No format means no file."); + Assert.That(FileExportFormat.UNKNOWN.IsPlainText, Is.False); + Assert.That(FileExportFormat.HTML.IsPlainText, Is.True, "A page the model wrote is a finished file, even though an entire answer needs Pandoc to become one."); + Assert.That(FileExportFormat.LATEX.IsPlainText, Is.True); + Assert.That(FileExportFormat.MARKDOWN.IsPlainText, Is.True); + Assert.That(FileExportFormat.CSV.IsPlainText, Is.True); + Assert.That(FileExportFormat.TSV.IsPlainText, Is.True); + Assert.That(FileExportFormat.SOURCE_CODE.IsPlainText, Is.True, "Code is text, whatever its language."); } } @@ -110,9 +110,9 @@ public sealed class FileExportFormatTests { using (Assert.EnterMultipleScope()) { - Assert.That(FileExportFormat.SOURCE_CODE.ToFileExtension(), Is.Empty, "Python and Rust share the format, but not the extension."); - Assert.That(FileExportFormat.SOURCE_CODE.ToFileTypeFilter(), Is.Null, "Without the language, the save dialog would offer the wrong files."); - Assert.That(FileExportFormatExtensions.ANSWER_FORMATS, Does.Not.Contain(FileExportFormat.SOURCE_CODE), "Code is one block out of an answer, never the answer itself."); + Assert.That(FileExportFormat.SOURCE_CODE.FileExtension, Is.Empty, "Python and Rust share the format, but not the extension."); + Assert.That(FileExportFormat.SOURCE_CODE.FileTypeFilter, Is.Null, "Without the language, the save dialog would offer the wrong files."); + Assert.That(FileExportFormat.AnswerFormats, Does.Not.Contain(FileExportFormat.SOURCE_CODE), "Code is one block out of an answer, never the answer itself."); } } @@ -124,7 +124,7 @@ public sealed class FileExportFormatTests { using (Assert.EnterMultipleScope()) { - Assert.That(FileExportFormatExtensions.TryFromCodeFenceLanguage(language, out var format), Is.False); + Assert.That(FileExportFormat.TryFromCodeFenceLanguage(language, out var format), Is.False); Assert.That(format, Is.EqualTo(FileExportFormat.NONE)); } } diff --git a/app/Tests/Tools/Mail/MailboxProviderTemplatesTests.cs b/app/Tests/Tools/Mail/MailboxProviderTemplatesTests.cs index 7f9391a78..359dd80c5 100644 --- a/app/Tests/Tools/Mail/MailboxProviderTemplatesTests.cs +++ b/app/Tests/Tools/Mail/MailboxProviderTemplatesTests.cs @@ -63,8 +63,8 @@ public sealed class MailboxProviderTemplatesTests [Test] public void EveryUsernameFormatHasItsOwnDescription() { - var descriptions = Enum.GetValues().Select(format => format.GetDescription()).ToList(); - var fallback = ((MailboxUsernameFormat)int.MaxValue).GetDescription(); + var descriptions = Enum.GetValues().Select(format => format.Description).ToList(); + var fallback = ((MailboxUsernameFormat)int.MaxValue).Description; using (Assert.EnterMultipleScope()) { diff --git a/app/Tests/Tools/PassageProvenanceTests.cs b/app/Tests/Tools/PassageProvenanceTests.cs index cbc61ee97..9f5638dc2 100644 --- a/app/Tests/Tools/PassageProvenanceTests.cs +++ b/app/Tests/Tools/PassageProvenanceTests.cs @@ -162,10 +162,10 @@ public sealed class PassageProvenanceTests { using (Assert.EnterMultipleScope()) { - Assert.That(Passage(HANDBOOK_URL, "text").GetProvenanceKind(), Is.EqualTo(ProvenanceKind.DATA_SOURCE_PASSAGE)); - Assert.That((Passage(HANDBOOK_URL, "text") with { Type = RetrievalContentType.TEXT_TRANSCRIPT }).GetProvenanceKind(), Is.EqualTo(ProvenanceKind.DATA_SOURCE_PASSAGE)); - Assert.That((Passage(HANDBOOK_URL, "text") with { Type = RetrievalContentType.TEXT_EMAIL }).GetProvenanceKind(), Is.EqualTo(ProvenanceKind.MAIL), "A mail is a mail, whether a mailbox data source or a tool handed it over."); - Assert.That((Passage(HANDBOOK_URL, "text") with { Type = RetrievalContentType.TEXT_WEBSITE }).GetProvenanceKind(), Is.EqualTo(ProvenanceKind.WEB_PAGE)); + Assert.That(Passage(HANDBOOK_URL, "text").ProvenanceKind, Is.EqualTo(ProvenanceKind.DATA_SOURCE_PASSAGE)); + Assert.That((Passage(HANDBOOK_URL, "text") with { Type = RetrievalContentType.TEXT_TRANSCRIPT }).ProvenanceKind, Is.EqualTo(ProvenanceKind.DATA_SOURCE_PASSAGE)); + Assert.That((Passage(HANDBOOK_URL, "text") with { Type = RetrievalContentType.TEXT_EMAIL }).ProvenanceKind, Is.EqualTo(ProvenanceKind.MAIL), "A mail is a mail, whether a mailbox data source or a tool handed it over."); + Assert.That((Passage(HANDBOOK_URL, "text") with { Type = RetrievalContentType.TEXT_WEBSITE }).ProvenanceKind, Is.EqualTo(ProvenanceKind.WEB_PAGE)); } } diff --git a/app/Tests/Tools/PowerPoint/LayoutPurposeTests.cs b/app/Tests/Tools/PowerPoint/LayoutPurposeTests.cs index 1c0f3be05..d0f9da225 100644 --- a/app/Tests/Tools/PowerPoint/LayoutPurposeTests.cs +++ b/app/Tests/Tools/PowerPoint/LayoutPurposeTests.cs @@ -15,9 +15,9 @@ public sealed class LayoutPurposeTests { foreach (var purpose in Enum.GetValues()) { - Assert.That(purpose.Label(), Is.Not.Empty, $"The kind of slide {purpose} has no label."); - Assert.That(purpose.Question(), Does.EndWith("?"), $"The kind of slide {purpose} has no question."); - Assert.That(purpose.PromptDescription(), Is.Not.Empty.And.Not.EndWith("."), $"The kind of slide {purpose} has no description, or one which ends where the rule for the model goes on."); + Assert.That(purpose.Label, Is.Not.Empty, $"The kind of slide {purpose} has no label."); + Assert.That(purpose.Question, Does.EndWith("?"), $"The kind of slide {purpose} has no question."); + Assert.That(purpose.PromptDescription, Is.Not.Empty.And.Not.EndWith("."), $"The kind of slide {purpose} has no description, or one which ends where the rule for the model goes on."); } } } @@ -28,7 +28,7 @@ public sealed class LayoutPurposeTests [Test] public void EveryKindOfSlideHasALabelOfItsOwn() { - var labels = Enum.GetValues().Select(purpose => purpose.Label()).ToList(); + var labels = Enum.GetValues().Select(purpose => purpose.Label).ToList(); Assert.That(labels, Is.Unique); } @@ -42,7 +42,7 @@ public sealed class LayoutPurposeTests [Test] public void TheKindsOfSlidesFollowTheOrderOfTheAreas() { - var areas = Enum.GetValues().Select(purpose => purpose.Area()).ToList(); + var areas = Enum.GetValues().Select(purpose => purpose.Area).ToList(); using (Assert.EnterMultipleScope()) { Assert.That(areas, Is.Ordered, "The kinds of an area stand together, and the areas follow their own order."); diff --git a/app/Tests/Tools/PowerPoint/PresentationTemplateTests.cs b/app/Tests/Tools/PowerPoint/PresentationTemplateTests.cs index e4e6b0e5e..66ae1d182 100644 --- a/app/Tests/Tools/PowerPoint/PresentationTemplateTests.cs +++ b/app/Tests/Tools/PowerPoint/PresentationTemplateTests.cs @@ -433,7 +433,7 @@ public sealed class PresentationTemplateTests (PlaceholderRole.TEXT, 3, StackedHeadings.THIRD_TEXT, 8U), }), "The copies are numbered after the slots of the layout, in reading order."); Assert.That(slide.SlotCopies.Select(copy => copy.Slot.Capacity), Is.EqualTo(new TextCapacity?[] { new TextCapacity(1, 14), new TextCapacity(3, 25), new TextCapacity(1, 18), new TextCapacity(3, 25) }), "A copy holds what its size allows, as a moved slot does."); - Assert.That(slide.Slots.Select(slot => $"{slot.Role.CatalogName()} {slot.Ordinal}"), Is.EqualTo(new[] { "title 1", "label 1", "text 1", "label 2", "text 2", "label 3", "text 3" })); + Assert.That(slide.Slots.Select(slot => $"{slot.Role.CatalogName} {slot.Ordinal}"), Is.EqualTo(new[] { "title 1", "label 1", "text 1", "label 2", "text 2", "label 3", "text 3" })); Assert.That(slide.Contents.Select(content => (content.Slot.Role, content.Text)), Is.EqualTo(new[] { (PlaceholderRole.TITLE, "Missions"), @@ -500,7 +500,7 @@ public sealed class PresentationTemplateTests using (Assert.EnterMultipleScope()) { Assert.That(slide.SlotCopies.Select(copy => (copy.Slot.Ordinal, copy.Slot.Bounds)), Is.EqualTo(new[] { (2, upperRight), (3, lowerRight) })); - Assert.That(slide.Slots.Select(slot => $"{slot.Role.CatalogName()} {slot.Ordinal}"), Is.EqualTo(new[] { "title 1", "label 1", "text 2", "text 1", "text 3" }), "The slots of the layout keep their numbers; a copy goes where a reader comes across it."); + Assert.That(slide.Slots.Select(slot => $"{slot.Role.CatalogName} {slot.Ordinal}"), Is.EqualTo(new[] { "title 1", "label 1", "text 2", "text 1", "text 3" }), "The slots of the layout keep their numbers; a copy goes where a reader comes across it."); } } diff --git a/app/Tests/Tools/SourceCodeLanguagesTests.cs b/app/Tests/Tools/SourceCodeLanguagesTests.cs index d4e9f9a0d..6b62471a5 100644 --- a/app/Tests/Tools/SourceCodeLanguagesTests.cs +++ b/app/Tests/Tools/SourceCodeLanguagesTests.cs @@ -121,7 +121,7 @@ public sealed class SourceCodeLanguagesTests [Test] public void NoAliasNamesAFormatOfItsOwn() { - // FileExportFormatExtensions.TryFromCodeFenceLanguage is asked first, so such an entry would never be found: - Assert.That(SourceCodeLanguages.Aliases.Where(alias => FileExportFormatExtensions.TryFromCodeFenceLanguage(alias, out _)), Is.Empty); + // FileExportFormat.TryFromCodeFenceLanguage is asked first, so such an entry would never be found: + Assert.That(SourceCodeLanguages.Aliases.Where(alias => FileExportFormat.TryFromCodeFenceLanguage(alias, out _)), Is.Empty); } } \ No newline at end of file diff --git a/app/Tests/Tools/SourcePassageTests.cs b/app/Tests/Tools/SourcePassageTests.cs index 7fe5822c0..0518dc62f 100644 --- a/app/Tests/Tools/SourcePassageTests.cs +++ b/app/Tests/Tools/SourcePassageTests.cs @@ -279,8 +279,8 @@ public sealed class SourcePassageTests { using (Assert.EnterMultipleScope()) { - Assert.That((Passage(HANDBOOK_URL, "Welcome.") with { Type = RetrievalContentType.TEXT_TRANSCRIPT }).IsTranscript(), Is.True); - Assert.That(Passage(HANDBOOK_URL, "Welcome.").IsTranscript(), Is.False); + Assert.That((Passage(HANDBOOK_URL, "Welcome.") with { Type = RetrievalContentType.TEXT_TRANSCRIPT }).IsTranscript, Is.True); + Assert.That(Passage(HANDBOOK_URL, "Welcome.").IsTranscript, Is.False); } } diff --git a/app/Tests/Tools/ToolCalling/MailPassageTests.cs b/app/Tests/Tools/ToolCalling/MailPassageTests.cs index e90889c35..b4860b232 100644 --- a/app/Tests/Tools/ToolCalling/MailPassageTests.cs +++ b/app/Tests/Tools/ToolCalling/MailPassageTests.cs @@ -65,7 +65,7 @@ public sealed class MailPassageTests Assert.That(new[] { passage }.GetPassagesOf(MAIL_SOURCE), Is.EqualTo(new[] { passage }), "Only a passage under its source gets the eye next to it."); Assert.That(passage.Path, Is.Empty, "The address of a mail names it for AI Studio only, so there is nothing to copy or open."); Assert.That(passage.DataSourceName, Is.EqualTo(MAIL_SOURCE.Title)); - Assert.That(passage.GetProvenanceKind(), Is.EqualTo(ProvenanceKind.MAIL)); + Assert.That(passage.ProvenanceKind, Is.EqualTo(ProvenanceKind.MAIL)); } } } \ No newline at end of file diff --git a/app/Tests/Tools/ToolCalling/ToolOutboundDataTests.cs b/app/Tests/Tools/ToolCalling/ToolOutboundDataTests.cs index 748f60a5c..9f8dee751 100644 --- a/app/Tests/Tools/ToolCalling/ToolOutboundDataTests.cs +++ b/app/Tests/Tools/ToolCalling/ToolOutboundDataTests.cs @@ -140,7 +140,7 @@ public sealed class ToolOutboundDataTests : ToolRegistryTestBase Assert.That(hasRun, Is.False, "The mail would already have left AI Studio."); Assert.That(outcome.Trace.Status, Is.EqualTo(ToolInvocationTraceStatus.BLOCKED)); Assert.That(outcome.Content, Does.Contain("Work mailbox"), "The user learns which mailbox stands in the way."); - Assert.That(outcome.Content, Does.Contain(OutboundDataRestriction.ONLY_LINKS_FROM_CHAT.GetName())); + Assert.That(outcome.Content, Does.Contain(OutboundDataRestriction.ONLY_LINKS_FROM_CHAT.Name)); } } @@ -154,7 +154,7 @@ public sealed class ToolOutboundDataTests : ToolRegistryTestBase { Assert.That(message, Does.Contain("removed since")); Assert.That(message, Does.Not.Contain("Private mailbox"), "Another mailbox did not restrict the chat."); - Assert.That(message, Does.Contain(OutboundDataRestriction.ONLY_CONFIGURED_SERVICES.GetName()), "The restriction stays, so the user still learns why."); + Assert.That(message, Does.Contain(OutboundDataRestriction.ONLY_CONFIGURED_SERVICES.Name), "The restriction stays, so the user still learns why."); } } @@ -168,7 +168,7 @@ public sealed class ToolOutboundDataTests : ToolRegistryTestBase { Assert.That(message, Does.Contain("Confluence wiki"), "The user learns that the wiki stands in the way."); Assert.That(message, Does.Not.Contain("mailbox"), "No mailbox restricted the chat."); - Assert.That(message, Does.Contain(OutboundDataRestriction.ONLY_LINKS_FROM_CHAT.GetName())); + Assert.That(message, Does.Contain(OutboundDataRestriction.ONLY_LINKS_FROM_CHAT.Name)); } } @@ -182,7 +182,7 @@ public sealed class ToolOutboundDataTests : ToolRegistryTestBase { Assert.That(message, Does.Contain("intranet.example.org"), "The user learns which page stands in the way."); Assert.That(message, Does.Not.Contain("mailbox"), "No mailbox restricted the chat."); - Assert.That(message, Does.Contain(OutboundDataRestriction.ONLY_CONFIGURED_SERVICES.GetName())); + Assert.That(message, Does.Contain(OutboundDataRestriction.ONLY_CONFIGURED_SERVICES.Name)); } } @@ -196,7 +196,7 @@ public sealed class ToolOutboundDataTests : ToolRegistryTestBase { Assert.That(message, Does.Contain("Project files"), "The user learns which data source stands in the way."); Assert.That(message, Does.Not.Contain("mailbox"), "No mailbox restricted the chat."); - Assert.That(message, Does.Contain(OutboundDataRestriction.ONLY_LINKS_FROM_CHAT.GetName())); + Assert.That(message, Does.Contain(OutboundDataRestriction.ONLY_LINKS_FROM_CHAT.Name)); } } @@ -210,7 +210,7 @@ public sealed class ToolOutboundDataTests : ToolRegistryTestBase { Assert.That(message, Does.Contain("removed since")); Assert.That(message, Does.Not.Contain("Minutes"), "Another data source did not restrict the chat."); - Assert.That(message, Does.Contain(OutboundDataRestriction.ONLY_CONFIGURED_SERVICES.GetName()), "The restriction stays, so the user still learns why."); + Assert.That(message, Does.Contain(OutboundDataRestriction.ONLY_CONFIGURED_SERVICES.Name), "The restriction stays, so the user still learns why."); } } diff --git a/app/Tests/Tools/Validation/MailboxValidationTests.cs b/app/Tests/Tools/Validation/MailboxValidationTests.cs index 8b03ab12b..847336003 100644 --- a/app/Tests/Tools/Validation/MailboxValidationTests.cs +++ b/app/Tests/Tools/Validation/MailboxValidationTests.cs @@ -37,7 +37,7 @@ public sealed class MailboxValidationTests [TestCase(MailboxTransportSecurity.SSL_ON_CONNECT, ExpectedResult = 993)] [TestCase(MailboxTransportSecurity.STARTTLS, ExpectedResult = 143)] [TestCase(MailboxTransportSecurity.UNKNOWN, ExpectedResult = null)] - public int? EachEncryptionComesWithItsUsualPort(MailboxTransportSecurity transportSecurity) => transportSecurity.GetUsualPort(); + public int? EachEncryptionComesWithItsUsualPort(MailboxTransportSecurity transportSecurity) => transportSecurity.UsualPort; [TestCase(0, ExpectedResult = false)] [TestCase(DataSourceValidation.MIN_ATTACHMENT_SIZE_MEGABYTES, ExpectedResult = true)] diff --git a/documentation/compatibility-shims/2026-06-self-hosted-secret-id.md b/documentation/compatibility-shims/2026-06-self-hosted-secret-id.md index 8e38a2c18..c9b70904e 100644 --- a/documentation/compatibility-shims/2026-06-self-hosted-secret-id.md +++ b/documentation/compatibility-shims/2026-06-self-hosted-secret-id.md @@ -26,5 +26,5 @@ This applies to LLM provider, embedding provider, and transcription provider API - Remove `LEGACY_SELF_HOSTED_SECRET_ID_DE`. - Remove `LegacySelfHostedAPIKeys`. - Remove legacy lookup, migration, and cleanup calls from API key read, write, and delete paths. -- Keep `LLMProvidersExtensions.ToSecretId()` and the canonical `Self-hosted` namespace. +- Keep `LLMProvidersExtensions.SecretId` and the canonical `Self-hosted` namespace. - Update this document's status to `Removed`. \ No newline at end of file