mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-13 23:28:41 +00:00
Added the choice between formal and informal address to the whole app (#1200)
This commit is contained in:
1 parent
382db4b8d0
commit
c9a376f742
342 files changed
+14378
-1893
No files matched your search
+7
-5
@@ -38,6 +38,8 @@ public sealed class ConfluenceSearchTool(WebPageRetrievalService webPageRetrieva
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ConfluenceSearchTool).Namespace, nameof(ConfluenceSearchTool));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(ConfluenceSearchTool).Namespace, nameof(ConfluenceSearchTool));
|
||||
|
||||
private const string BASE_URL_SETTING = "baseUrl";
|
||||
private const string TIMEOUT_SECONDS_SETTING = "timeoutSeconds";
|
||||
private const string QUERY_ARGUMENT = "query";
|
||||
@@ -137,7 +139,7 @@ public sealed class ConfluenceSearchTool(WebPageRetrievalService webPageRetrieva
|
||||
|
||||
public string GetDisplayName() => TB("Search Confluence");
|
||||
|
||||
public string GetDescription() => TB("Find pages in your company's Confluence wiki.");
|
||||
public string GetDescription() => TA("Find pages in your company's Confluence wiki.");
|
||||
|
||||
public string GetSettingsFieldLabel(string fieldName, ToolSettingsFieldDefinition fieldDefinition) => fieldName switch
|
||||
{
|
||||
@@ -148,7 +150,7 @@ public sealed class ConfluenceSearchTool(WebPageRetrievalService webPageRetrieva
|
||||
|
||||
public string GetSettingsFieldDescription(string fieldName, ToolSettingsFieldDefinition fieldDefinition) => fieldName switch
|
||||
{
|
||||
BASE_URL_SETTING => TB("The HTTPS address of your Confluence Data Center wiki, including its path if present, such as https://wiki.example.org/confluence/. Confluence Cloud is not supported yet. When your wiki has a private or VPN address, also add its host to the allowed private hosts of Read Web Page, which opens the pages found. Where a chat may send data after a search is decided by the setting 'Where a chat may send data after reading internal pages' of Read Web Page, which applies to wiki pages as well."),
|
||||
BASE_URL_SETTING => TA("The HTTPS address of your Confluence Data Center wiki, including its path if present, such as https://wiki.example.org/confluence/. Confluence Cloud is not supported yet. When your wiki has a private or VPN address, also add its host to the allowed private hosts of Read Web Page, which opens the pages found. Where a chat may send data after a search is decided by the setting 'Where a chat may send data after reading internal pages' of Read Web Page, which applies to wiki pages as well."),
|
||||
TIMEOUT_SECONDS_SETTING => TB("(Optional) Search request timeout in seconds."),
|
||||
_ => TB(fieldDefinition.Description),
|
||||
};
|
||||
@@ -165,7 +167,7 @@ public sealed class ConfluenceSearchTool(WebPageRetrievalService webPageRetrieva
|
||||
return Task.FromResult<ToolConfigurationState?>(new ToolConfigurationState
|
||||
{
|
||||
IsConfigured = false,
|
||||
Message = TB("Enter a valid HTTPS Confluence base URL without a query or fragment."),
|
||||
Message = TA("Enter a valid HTTPS Confluence base URL without a query or fragment."),
|
||||
});
|
||||
|
||||
if (!ToolSettingsValueParser.TryReadBoundedOptionalPositiveInt(settingsValues, TIMEOUT_SECONDS_SETTING, MAX_TIMEOUT_SECONDS,
|
||||
@@ -193,7 +195,7 @@ public sealed class ConfluenceSearchTool(WebPageRetrievalService webPageRetrieva
|
||||
// a High-confidence provider.
|
||||
//
|
||||
if (context.ProviderConfidence < ConfidenceLevel.HIGH)
|
||||
throw new ToolExecutionBlockedException(TB("Searching your company's wiki requires a High-confidence provider."));
|
||||
throw new ToolExecutionBlockedException(TA("Searching your company's wiki requires a High-confidence provider."));
|
||||
|
||||
if (!TryParseBaseUrl(context.SettingsValues.GetValueOrDefault(BASE_URL_SETTING), out var baseUrl))
|
||||
throw new InvalidOperationException(TB("The Confluence base URL is not configured correctly."));
|
||||
@@ -247,7 +249,7 @@ public sealed class ConfluenceSearchTool(WebPageRetrievalService webPageRetrieva
|
||||
throw new InvalidOperationException(TB("Confluence redirected the search outside the configured wiki."));
|
||||
|
||||
if (IsLoginPage(page.FinalUrl))
|
||||
throw new InvalidOperationException(TB("Confluence asked for a sign-in instead of showing search results. AI Studio signs in with your operating system account only when your wiki has a private or VPN address, and either the wiki did not accept that sign-in or its address is public. Open the wiki in your browser to check your access."));
|
||||
throw new InvalidOperationException(TA("Confluence asked for a sign-in instead of showing search results. AI Studio signs in with your operating system account only when your wiki has a private or VPN address, and either the wiki did not accept that sign-in or its address is public. Open the wiki in your browser to check your access."));
|
||||
|
||||
var markdown = retrievedPage.ExtractedPage.Markdown;
|
||||
if (string.IsNullOrWhiteSpace(markdown))
|
||||
|
||||
+3
-1
@@ -31,6 +31,8 @@ public sealed class CountMailsTool(SettingsManager settingsManager, MailboxRetri
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(CountMailsTool).Namespace, nameof(CountMailsTool));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(CountMailsTool).Namespace, nameof(CountMailsTool));
|
||||
|
||||
private const string GROUP_BY_ARGUMENT = "group_by";
|
||||
private const string TOOL_ACTION = "count";
|
||||
|
||||
@@ -124,7 +126,7 @@ public sealed class CountMailsTool(SettingsManager settingsManager, MailboxRetri
|
||||
|
||||
public string GetDisplayName() => TB("Count Mails");
|
||||
|
||||
public string GetDescription() => TB("Lets the AI count the mails in your mailboxes, e.g., the unread ones or those in a project folder.");
|
||||
public string GetDescription() => TA("Lets the AI count the mails in your mailboxes, e.g., the unread ones or those in a project folder.");
|
||||
|
||||
public Task<ToolConfigurationState?> ValidateConfigurationAsync(ToolDefinition definition, IReadOnlyDictionary<string, string> settingsValues, CancellationToken token = default) =>
|
||||
Task.FromResult(MailToolConfiguration.GetState(settingsManager));
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@ namespace AIStudio.Tools.ToolCallingSystem.ToolCallingImplementations.Mailboxes;
|
||||
/// </summary>
|
||||
internal static class MailToolConfiguration
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(MailToolConfiguration).Namespace, nameof(MailToolConfiguration));
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(MailToolConfiguration).Namespace, nameof(MailToolConfiguration));
|
||||
|
||||
/// <summary>
|
||||
/// The state the selection shows for a mail tool: not set up while there is no mailbox at all.
|
||||
@@ -24,6 +24,6 @@ internal static class MailToolConfiguration
|
||||
: new ToolConfigurationState
|
||||
{
|
||||
IsConfigured = false,
|
||||
Message = TB("To use this tool, add a mailbox to your data sources first."),
|
||||
Message = TA("To use this tool, add a mailbox to your data sources first."),
|
||||
};
|
||||
}
|
||||
+3
-1
@@ -17,6 +17,8 @@ public sealed class MailboxToolCollection : IToolCollection
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(MailboxToolCollection).Namespace, nameof(MailboxToolCollection));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(MailboxToolCollection).Namespace, nameof(MailboxToolCollection));
|
||||
|
||||
public ToolCollectionDefinition GetDefinition() => new()
|
||||
{
|
||||
Id = ToolSelectionRules.MAILBOXES_COLLECTION_ID,
|
||||
@@ -29,5 +31,5 @@ public sealed class MailboxToolCollection : IToolCollection
|
||||
|
||||
public string GetDisplayName() => TB("Mailboxes");
|
||||
|
||||
public string GetDescription() => TB("Lets the AI search, read, and count the mails in your mailboxes, including their attachments.");
|
||||
public string GetDescription() => TA("Lets the AI search, read, and count the mails in your mailboxes, including their attachments.");
|
||||
}
|
||||
+3
-1
@@ -28,6 +28,8 @@ public sealed class ReadMailTool(SettingsManager settingsManager, MailboxRetriev
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ReadMailTool).Namespace, nameof(ReadMailTool));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(ReadMailTool).Namespace, nameof(ReadMailTool));
|
||||
|
||||
private const string MAIL_ID_ARGUMENT = "mail_id";
|
||||
private const string ATTACHMENT_ARGUMENT = "attachment";
|
||||
private const string INCLUDE_HEADERS_ARGUMENT = "include_headers";
|
||||
@@ -108,7 +110,7 @@ public sealed class ReadMailTool(SettingsManager settingsManager, MailboxRetriev
|
||||
|
||||
public string GetDisplayName() => TB("Read Mail");
|
||||
|
||||
public string GetDescription() => TB("Lets the AI read the mails it found in your mailboxes, including their attachments.");
|
||||
public string GetDescription() => TA("Lets the AI read the mails it found in your mailboxes, including their attachments.");
|
||||
|
||||
public Task<ToolConfigurationState?> ValidateConfigurationAsync(ToolDefinition definition, IReadOnlyDictionary<string, string> settingsValues, CancellationToken token = default) =>
|
||||
Task.FromResult(MailToolConfiguration.GetState(settingsManager));
|
||||
|
||||
+3
-1
@@ -31,6 +31,8 @@ public sealed class SearchMailsTool(SettingsManager settingsManager, MailboxRetr
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(SearchMailsTool).Namespace, nameof(SearchMailsTool));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(SearchMailsTool).Namespace, nameof(SearchMailsTool));
|
||||
|
||||
private const string QUERY_ARGUMENT = "query";
|
||||
private const string PAGE_ARGUMENT = "page";
|
||||
private const string TOOL_ACTION = "search";
|
||||
@@ -187,7 +189,7 @@ public sealed class SearchMailsTool(SettingsManager settingsManager, MailboxRetr
|
||||
|
||||
public string GetDisplayName() => TB("Search Mails");
|
||||
|
||||
public string GetDescription() => TB("Lets the AI search your mailboxes, list mails by sender, date, or flags, and quote what they say.");
|
||||
public string GetDescription() => TA("Lets the AI search your mailboxes, list mails by sender, date, or flags, and quote what they say.");
|
||||
|
||||
public Task<ToolConfigurationState?> ValidateConfigurationAsync(ToolDefinition definition, IReadOnlyDictionary<string, string> settingsValues, CancellationToken token = default) =>
|
||||
Task.FromResult(MailToolConfiguration.GetState(settingsManager));
|
||||
|
||||
+3
-1
@@ -27,6 +27,8 @@ public sealed class CalculateTool(SettingsManager settingsManager, MathComputati
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(CalculateTool).Namespace, nameof(CalculateTool));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(CalculateTool).Namespace, nameof(CalculateTool));
|
||||
|
||||
private const string EXPRESSION_ARGUMENT = "expression";
|
||||
private const string DIGITS_ARGUMENT = "digits";
|
||||
|
||||
@@ -76,7 +78,7 @@ public sealed class CalculateTool(SettingsManager settingsManager, MathComputati
|
||||
|
||||
public string GetDisplayName() => TB("Calculate");
|
||||
|
||||
public string GetDescription() => TB("Lets the AI calculate exactly instead of guessing digits, e.g., fractions, roots, or integrals, and check an equation. Everything is computed on your computer.");
|
||||
public string GetDescription() => TA("Lets the AI calculate exactly instead of guessing digits, e.g., fractions, roots, or integrals, and check an equation. Everything is computed on your computer.");
|
||||
|
||||
public async Task<ToolExecutionResult> ExecuteAsync(JsonElement arguments, ToolExecutionContext context, CancellationToken token = default)
|
||||
{
|
||||
|
||||
+3
-1
@@ -30,6 +30,8 @@ public sealed class ComputeSymbolicallyTool(SettingsManager settingsManager, Mat
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ComputeSymbolicallyTool).Namespace, nameof(ComputeSymbolicallyTool));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(ComputeSymbolicallyTool).Namespace, nameof(ComputeSymbolicallyTool));
|
||||
|
||||
private const string OPERATION_ARGUMENT = "operation";
|
||||
private const string EXPRESSION_ARGUMENT = "expression";
|
||||
private const string VARIABLE_ARGUMENT = "variable";
|
||||
@@ -122,7 +124,7 @@ public sealed class ComputeSymbolicallyTool(SettingsManager settingsManager, Mat
|
||||
|
||||
public string GetDisplayName() => TB("Compute Symbolically");
|
||||
|
||||
public string GetDescription() => TB("Lets the AI work with formulas: simplify and factor them, differentiate and integrate them, take limits, and solve equations. Every result is checked numerically where possible, right on your computer.");
|
||||
public string GetDescription() => TA("Lets the AI work with formulas: simplify and factor them, differentiate and integrate them, take limits, and solve equations. Every result is checked numerically where possible, right on your computer.");
|
||||
|
||||
public async Task<ToolExecutionResult> ExecuteAsync(JsonElement arguments, ToolExecutionContext context, CancellationToken token = default)
|
||||
{
|
||||
|
||||
+3
-1
@@ -18,6 +18,8 @@ public sealed class MathematicsToolCollection : IToolCollection
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(MathematicsToolCollection).Namespace, nameof(MathematicsToolCollection));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(MathematicsToolCollection).Namespace, nameof(MathematicsToolCollection));
|
||||
|
||||
public ToolCollectionDefinition GetDefinition() => new()
|
||||
{
|
||||
Id = ToolSelectionRules.MATHEMATICS_COLLECTION_ID,
|
||||
@@ -30,5 +32,5 @@ public sealed class MathematicsToolCollection : IToolCollection
|
||||
|
||||
public string GetDisplayName() => TB("Mathematics");
|
||||
|
||||
public string GetDescription() => TB("Lets the AI calculate exactly and work with formulas, such as solving equations or checking an integral, right on your computer.");
|
||||
public string GetDescription() => TA("Lets the AI calculate exactly and work with formulas, such as solving equations or checking an integral, right on your computer.");
|
||||
}
|
||||
+8
-6
@@ -15,6 +15,8 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ReadWebPageTool).Namespace, nameof(ReadWebPageTool));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(ReadWebPageTool).Namespace, nameof(ReadWebPageTool));
|
||||
|
||||
private const int DEFAULT_TIMEOUT_SECONDS = 60;
|
||||
private const int DEFAULT_MAX_CONTENT_CHARACTERS = 30000;
|
||||
private const int MAX_TIMEOUT_SECONDS = 240;
|
||||
@@ -111,7 +113,7 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ
|
||||
|
||||
public string GetDisplayName() => TB("Read Web Page");
|
||||
|
||||
public string GetDescription() => TB("Load a web page and extract its readable content, links, and page details.");
|
||||
public string GetDescription() => TA("Load a web page and extract its readable content, links, and page details.");
|
||||
|
||||
public string GetSettingsFieldLabel(string fieldName, ToolSettingsFieldDefinition fieldDefinition) => fieldName switch
|
||||
{
|
||||
@@ -127,9 +129,9 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ
|
||||
{
|
||||
TIMEOUT_SECONDS_SETTING => TB("(Optional) HTTP timeout for loading a web page in seconds."),
|
||||
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.Name, OutboundDataRestriction.ONLY_CONFIGURED_SERVICES.Name),
|
||||
ALLOWED_PRIVATE_HOSTS_SETTING => TA("(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 => TA("(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(TA("(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 has 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),
|
||||
};
|
||||
|
||||
@@ -175,7 +177,7 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ
|
||||
// may be misspelled. Guessing what it meant would decide on the organization's behalf
|
||||
// whether the AI may choose addresses, so it is reported instead:
|
||||
//
|
||||
if (!ToolSettingsValueParser.TryValidateOptionValue(settingsValues, FREE_ADDRESS_CHOICE_SETTING, ToolSettingsOptionSources.FREE_ADDRESS_CHOICE, TB("The setting '{0}' holds the value '{1}', which is not one of the available options. Please choose one of the offered values."), out var freeAddressChoiceError))
|
||||
if (!ToolSettingsValueParser.TryValidateOptionValue(settingsValues, FREE_ADDRESS_CHOICE_SETTING, ToolSettingsOptionSources.FREE_ADDRESS_CHOICE, TA("The setting '{0}' holds the value '{1}', which is not one of the available options. Please choose one of the offered values."), out var freeAddressChoiceError))
|
||||
{
|
||||
return Task.FromResult<ToolConfigurationState?>(new ToolConfigurationState
|
||||
{
|
||||
@@ -185,7 +187,7 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ
|
||||
}
|
||||
|
||||
// Reported for the same reason: a guess would decide where intranet content may go.
|
||||
if (!ToolSettingsValueParser.TryValidateOptionValue(settingsValues, INTERNAL_PAGE_OUTBOUND_DATA_RESTRICTION_SETTING, ToolSettingsOptionSources.OUTBOUND_DATA_RESTRICTION, TB("The setting '{0}' holds the value '{1}', which is not one of the available options. Please choose one of the offered values."), out var restrictionError))
|
||||
if (!ToolSettingsValueParser.TryValidateOptionValue(settingsValues, INTERNAL_PAGE_OUTBOUND_DATA_RESTRICTION_SETTING, ToolSettingsOptionSources.OUTBOUND_DATA_RESTRICTION, TA("The setting '{0}' holds the value '{1}', which is not one of the available options. Please choose one of the offered values."), out var restrictionError))
|
||||
{
|
||||
return Task.FromResult<ToolConfigurationState?>(new ToolConfigurationState
|
||||
{
|
||||
|
||||
+3
-1
@@ -35,6 +35,8 @@ public sealed class SemanticSearchTool(SettingsManager settingsManager, DataSour
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(SemanticSearchTool).Namespace, nameof(SemanticSearchTool));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(SemanticSearchTool).Namespace, nameof(SemanticSearchTool));
|
||||
|
||||
private const string QUERY_ARGUMENT = "query";
|
||||
private const string DATA_SOURCE_IDS_ARGUMENT = "data_source_ids";
|
||||
private const string PAGE_ARGUMENT = "page";
|
||||
@@ -345,7 +347,7 @@ public sealed class SemanticSearchTool(SettingsManager settingsManager, DataSour
|
||||
|
||||
public string GetDisplayName() => TB("Semantic Search");
|
||||
|
||||
public string GetDescription() => TB("Lets the AI search the data sources of your chat itself, whenever a question calls for it.");
|
||||
public string GetDescription() => TA("Lets the AI search the data sources of your chat itself, whenever a question calls for it.");
|
||||
|
||||
public async Task<ToolExecutionResult> ExecuteAsync(JsonElement arguments, ToolExecutionContext context, CancellationToken token = default)
|
||||
{
|
||||
|
||||
+3
-1
@@ -14,6 +14,8 @@ public sealed class SearXNGSearchBackend : IWebSearchBackend
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(SearXNGSearchBackend).Namespace, nameof(SearXNGSearchBackend));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(SearXNGSearchBackend).Namespace, nameof(SearXNGSearchBackend));
|
||||
|
||||
private const string SETTINGS_GROUP = "searxng";
|
||||
|
||||
private const string BASE_URL_SETTING = $"{SETTINGS_GROUP}.baseUrl";
|
||||
@@ -59,7 +61,7 @@ public sealed class SearXNGSearchBackend : IWebSearchBackend
|
||||
|
||||
public string GetSettingsFieldDescription(string fieldName) => fieldName switch
|
||||
{
|
||||
BASE_URL_SETTING => TB("Base URL of the SearXNG instance. You can enter either the instance root URL or the /search endpoint. The instance must have the JSON format enabled, which means 'json' has to be listed under 'search.formats' in its settings.yml. Public instances usually serve only the web interface and additionally block automated requests, so a self-hosted instance is the reliable option."),
|
||||
BASE_URL_SETTING => TA("Base URL of the SearXNG instance. You can enter either the instance root URL or the /search endpoint. The instance must have the JSON format enabled, which means 'json' has to be listed under 'search.formats' in its settings.yml. Public instances usually serve only the web interface and additionally block automated requests, so a self-hosted instance is the reliable option."),
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
|
||||
+4
-2
@@ -18,6 +18,8 @@ public sealed class StaanSearchBackend : IWebSearchBackend
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(StaanSearchBackend).Namespace, nameof(StaanSearchBackend));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(StaanSearchBackend).Namespace, nameof(StaanSearchBackend));
|
||||
|
||||
private const string SETTINGS_GROUP = "staan";
|
||||
|
||||
private const string API_KEY_SETTING = $"{SETTINGS_GROUP}.apiKey";
|
||||
@@ -85,7 +87,7 @@ public sealed class StaanSearchBackend : IWebSearchBackend
|
||||
|
||||
public string GetSettingsFieldDescription(string fieldName) => fieldName switch
|
||||
{
|
||||
API_KEY_SETTING => TB("Your Staan API key. It is kept in your operating system's keyring, not in a settings file. Staan is a European search index; the first requests are free of charge, after which searching is billed per thousand requests."),
|
||||
API_KEY_SETTING => TA("Your Staan API key. It is kept in your operating system's keyring, not in a settings file. Staan is a European search index; the first requests are free of charge, after which searching is billed per thousand requests."),
|
||||
MARKET_SETTING => TB("The market Staan searches in. Staan searches one market at a time and offers only these three. When the AI model asks for German, English, or French, the matching market is used no matter what is chosen here; this setting decides what happens for every other language and when no language is requested at all."),
|
||||
|
||||
_ => string.Empty,
|
||||
@@ -113,7 +115,7 @@ public sealed class StaanSearchBackend : IWebSearchBackend
|
||||
if (string.IsNullOrWhiteSpace(market) || IsSupportedMarket(market))
|
||||
return true;
|
||||
|
||||
error = string.Format(TB("The configured Staan market '{0}' is not one of the markets Staan offers. Please choose one of these: {1}."), market, string.Join(", ", SUPPORTED_MARKETS));
|
||||
error = string.Format(TA("The configured Staan market '{0}' is not one of the markets Staan offers. Please choose one of these: {1}."), market, string.Join(", ", SUPPORTED_MARKETS));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -15,6 +15,8 @@ public sealed class TavilySearchBackend : IWebSearchBackend
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(TavilySearchBackend).Namespace, nameof(TavilySearchBackend));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(TavilySearchBackend).Namespace, nameof(TavilySearchBackend));
|
||||
|
||||
private const string SETTINGS_GROUP = "tavily";
|
||||
|
||||
private const string API_KEY_SETTING = $"{SETTINGS_GROUP}.apiKey";
|
||||
@@ -78,8 +80,8 @@ public sealed class TavilySearchBackend : IWebSearchBackend
|
||||
|
||||
public string GetSettingsFieldDescription(string fieldName) => fieldName switch
|
||||
{
|
||||
API_KEY_SETTING => TB("Your Tavily API key. It is kept in your operating system's keyring, not in a settings file. Tavily grants 1,000 requests per month without a credit card, which is enough for everyday use."),
|
||||
SEARCH_DEPTH_SETTING => TB("How thoroughly Tavily searches. A basic search costs one of your monthly requests, an advanced search costs two and looks at more of each page before deciding how well it matches. Basic is the sensible choice unless you notice that results are missing the point."),
|
||||
API_KEY_SETTING => TA("Your Tavily API key. It is kept in your operating system's keyring, not in a settings file. Tavily grants 1,000 requests per month without a credit card, which is enough for everyday use."),
|
||||
SEARCH_DEPTH_SETTING => TA("How thoroughly Tavily searches. A basic search costs one of your monthly requests, an advanced search costs two and looks at more of each page before deciding how well it matches. Basic is the sensible choice unless you notice that results are missing the point."),
|
||||
|
||||
_ => string.Empty,
|
||||
};
|
||||
@@ -106,7 +108,7 @@ public sealed class TavilySearchBackend : IWebSearchBackend
|
||||
if (string.IsNullOrWhiteSpace(searchDepth) || IsSupportedSearchDepth(searchDepth))
|
||||
return true;
|
||||
|
||||
error = string.Format(TB("The configured Tavily search depth '{0}' is not one this app supports. Please choose one of these: {1}."), searchDepth, string.Join(", ", SUPPORTED_SEARCH_DEPTHS));
|
||||
error = string.Format(TA("The configured Tavily search depth '{0}' is not one this app supports. Please choose one of these: {1}."), searchDepth, string.Join(", ", SUPPORTED_SEARCH_DEPTHS));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -20,6 +20,8 @@ internal sealed class WebSearchDispatcher(IEnumerable<IWebSearchBackend> backend
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(WebSearchDispatcher).Namespace, nameof(WebSearchDispatcher));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(WebSearchDispatcher).Namespace, nameof(WebSearchDispatcher));
|
||||
|
||||
public IReadOnlyList<IWebSearchBackend> Backends { get; } = backends.OrderBy(backend => backend.Backend).ToList();
|
||||
|
||||
/// <summary>
|
||||
@@ -115,7 +117,7 @@ internal sealed class WebSearchDispatcher(IEnumerable<IWebSearchBackend> backend
|
||||
|
||||
var remainingBackends = backendsToAsk.Where(backend => backend.Capabilities.SupportsSafeSearch).ToList();
|
||||
if (remainingBackends.Count is 0)
|
||||
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."));
|
||||
throw new InvalidOperationException(TA("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.Name} was not asked, because it cannot filter explicit results and the configured safe search policy requires that.");
|
||||
|
||||
+12
-10
@@ -24,6 +24,8 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(WebSearchTool).Namespace, nameof(WebSearchTool));
|
||||
|
||||
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(WebSearchTool).Namespace, nameof(WebSearchTool));
|
||||
|
||||
//
|
||||
// The dispatcher holds the backends: which of them answers a search, and in which order,
|
||||
// is what it decides, so the order they are offered and tried in belongs to it rather than
|
||||
@@ -185,7 +187,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
|
||||
|
||||
public string GetDisplayName() => TB("Web Search");
|
||||
|
||||
public string GetDescription() => TB("Search the web with one of the configured search services and retrieve the readable content of the best matching pages.");
|
||||
public string GetDescription() => TA("Search the web with one of the configured search services and retrieve the readable content of the best matching pages.");
|
||||
|
||||
public string GetSettingsGroupLabel(string groupKey) => this.FindBackend(groupKey)?.GetSettingsGroupLabel() ?? groupKey;
|
||||
|
||||
@@ -221,9 +223,9 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
|
||||
|
||||
return fieldName switch
|
||||
{
|
||||
BACKEND_STRATEGY_SETTING => TB("What to do with the search services you configured. Asking them one after another moves on to the next one whenever the one before it found nothing, which is the sensible choice for almost everyone. Asking all of them at once combines their results and uses one request of every service for each search, which finds more but spends your free requests several times as fast. When this is not set, the services are asked one after another."),
|
||||
PRIMARY_BACKEND_SETTING => TB("Which search service to ask first, and the only one asked when you chose to use just the preferred one. When this is not set, the services are asked in a fixed order."),
|
||||
DEFAULT_LANGUAGE_SETTING => TB("The language to search in when the AI model does not ask for a specific one. This is required: without a language, many search engines return no results at all, and the search would come back empty without telling you why. Choose 'Any language' if you do not want to restrict the results."),
|
||||
BACKEND_STRATEGY_SETTING => TA("What to do with the search services you configured. Asking them one after another moves on to the next one whenever the one before it found nothing, which is the sensible choice for almost everyone. Asking all of them at once combines their results and uses one request of every service for each search, which finds more but spends your free requests several times as fast. When this is not set, the services are asked one after another."),
|
||||
PRIMARY_BACKEND_SETTING => TA("Which search service to ask first, and the only one asked when you chose to use just the preferred one. When this is not set, the services are asked in a fixed order."),
|
||||
DEFAULT_LANGUAGE_SETTING => TA("The language to search in when the AI model does not ask for a specific one. This is required: without a language, many search engines return no results at all, and the search would come back empty without telling you why. Choose 'Any language' if you do not want to restrict the results."),
|
||||
DEFAULT_SAFE_SEARCH_SETTING => TB("Optional safe search policy sent to the search service when configured."),
|
||||
MAX_RESULTS_SETTING => TB("Optional default maximum number of results returned to the model when the model does not provide a limit."),
|
||||
SEARCH_TIMEOUT_SECONDS_SETTING => TB("Optional HTTP timeout for the search request in seconds."),
|
||||
@@ -302,7 +304,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
|
||||
{
|
||||
var positiveIntegerErrorFormat = TB("The setting '{0}' must be a positive integer.");
|
||||
var maximumErrorFormat = TB("The setting '{0}' must be less than or equal to {1}.");
|
||||
var invalidOptionErrorFormat = TB("The setting '{0}' holds the value '{1}', which is not one of the available options. Please choose one of the offered values.");
|
||||
var invalidOptionErrorFormat = TA("The setting '{0}' holds the value '{1}', which is not one of the available options. Please choose one of the offered values.");
|
||||
|
||||
//
|
||||
// No backend field is required in the schema, because requiring one would mean every
|
||||
@@ -315,7 +317,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
|
||||
return Task.FromResult<ToolConfigurationState?>(new ToolConfigurationState
|
||||
{
|
||||
IsConfigured = false,
|
||||
Message = TB("Please configure at least one search service for the web search."),
|
||||
Message = TA("Please configure at least one search service for the web search."),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -362,7 +364,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
|
||||
return Task.FromResult<ToolConfigurationState?>(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.Name),
|
||||
Message = string.Format(TA("The preferred search service {0} is not configured. Please configure it, or choose one of the services you did configure."), primaryBackend.Value.Name),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -371,7 +373,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
|
||||
return Task.FromResult<ToolConfigurationState?>(new ToolConfigurationState
|
||||
{
|
||||
IsConfigured = false,
|
||||
Message = TB("Please choose the preferred search service, or let the services be used one after another."),
|
||||
Message = TA("Please choose the preferred search service, or let the services be used one after another."),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -412,7 +414,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
|
||||
return Task.FromResult<ToolConfigurationState?>(new ToolConfigurationState
|
||||
{
|
||||
IsConfigured = false,
|
||||
Message = TB("None of the configured search services can filter explicit results, but a safe search policy is configured. Please configure a search service that can filter, or set the safe search policy to off."),
|
||||
Message = TA("None of the configured search services can filter explicit results, but a safe search policy is configured. Please configure a search service that can filter, or set the safe search policy to off."),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -429,7 +431,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
|
||||
return Task.FromResult<ToolConfigurationState?>(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.Name),
|
||||
Message = string.Format(TA("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),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user