Changed private web pages and the Confluence search to require a High-confidence provider

This commit is contained in:
Thorsten Sommer 2026-09-23 16:31:21 +02:00
parent 56978d88f2
commit ad6b285c8d
Signed by untrusted user who does not match committer: tsommer
GPG Key ID: 371BBA77A02C0108
11 changed files with 34 additions and 51 deletions

View File

@ -37,20 +37,13 @@ public static class ChatThreadExtensions
}; };
// //
// A provider trusted by the organization's configuration may continue the thread whatever // The confidence axis is checked on its own: a provider trusted by configuration counts as
// confidence it requires, the same as the tools which put that data into the thread treat // self-hosted for data-source security, which is the check further down, but that trust
// it as equal to a High-confidence provider. Otherwise such a provider could run a tool // says nothing about how confidential the provider is. An organization which wants its
// and then be locked out of its own chat by the result. // contractually covered cloud provider to pass here raises its level through the custom
// confidence scheme instead.
// //
var isTrustedByConfiguration = provider switch if (providerConfidence < chatThread.RequiredProviderConfidence)
{
IProvider p => p.IsTrustedByConfiguration(settingsManager),
AIStudio.Settings.Provider p => p.IsTrustedByConfiguration(settingsManager),
_ => false,
};
if (providerConfidence < chatThread.RequiredProviderConfidence && !isTrustedByConfiguration)
return false; return false;
// The chat thread is available, but the data security is not specified. // The chat thread is available, but the data security is not specified.

View File

@ -741,13 +741,13 @@ CONFIG["SETTINGS"] = {}
-- Configure the minimum provider confidence level required for individual tools. -- Configure the minimum provider confidence level required for individual tools.
-- Tool IDs include: web_search, read_web_page, search_confluence -- Tool IDs include: web_search, read_web_page, search_confluence
-- Allowed values are: NONE, UNTRUSTED, VERY_LOW, LOW, MODERATE, MEDIUM, HIGH -- Allowed values are: NONE, UNTRUSTED, VERY_LOW, LOW, MODERATE, MEDIUM, HIGH
-- Defaults: web_search = VERY_LOW, read_web_page = VERY_LOW, search_confluence = VERY_LOW -- Defaults: web_search = VERY_LOW, read_web_page = VERY_LOW, search_confluence = HIGH
-- search_confluence also always requires a HIGH-confidence provider or one trusted by the -- search_confluence always searches with a HIGH-confidence provider only, whatever value is
-- organization, whatever value is set here. -- set here.
-- CONFIG["SETTINGS"]["DataTools.MinimumProviderConfidenceByToolId"] = { -- CONFIG["SETTINGS"]["DataTools.MinimumProviderConfidenceByToolId"] = {
-- ["web_search"] = "VERY_LOW", -- ["web_search"] = "VERY_LOW",
-- ["read_web_page"] = "VERY_LOW", -- ["read_web_page"] = "VERY_LOW",
-- ["search_confluence"] = "VERY_LOW" -- ["search_confluence"] = "HIGH"
-- } -- }
-- Configure the settings of individual tools. Keys are "<tool ID>.<field name>", values are -- Configure the settings of individual tools. Keys are "<tool ID>.<field name>", values are
@ -827,7 +827,7 @@ CONFIG["SETTINGS"] = {}
-- dosearchsite.action with the same web-page reader as read_web_page and uses -- dosearchsite.action with the same web-page reader as read_web_page and uses
-- the current user's operating-system sign-in, also when the wiki has public -- the current user's operating-system sign-in, also when the wiki has public
-- addresses. Redirects outside this URL are refused. A provider must have HIGH -- addresses. Redirects outside this URL are refused. A provider must have HIGH
-- confidence or be trusted by the organization to receive search results. -- confidence to receive search results.
-- timeoutSeconds Search request timeout in seconds, at most 120. Default: 30. -- timeoutSeconds Search request timeout in seconds, at most 120. Default: 30.
-- To read a found page, also configure read_web_page.allowedPrivateHosts if your wiki has a -- To read a found page, also configure read_web_page.allowedPrivateHosts if your wiki has a
-- private or VPN address, and select both tools for the chat or assistant. -- private or VPN address, and select both tools for the chat or assistant.
@ -940,8 +940,9 @@ CONFIG["SETTINGS"] = {}
-- Configure provider instances trusted by your organization for data-source security checks. -- Configure provider instances trusted by your organization for data-source security checks.
-- These IDs may refer to LLM providers, embedding providers, or transcription providers -- These IDs may refer to LLM providers, embedding providers, or transcription providers
-- defined in this configuration. Trusted providers are treated like self-hosted providers -- defined in this configuration. Trusted providers are treated like self-hosted providers
-- only for data-source security checks and related local data warnings. Trusted LLM providers -- only for data-source security checks and related local data warnings. This trust does not
-- can also use read_web_page for explicitly allowed private or VPN hosts. -- meet a required confidence level, for example of a local data source or a private web page;
-- raise the provider's level in the custom confidence scheme above for that.
-- --
-- Replaces, does not merge: a configuration with a higher priority replaces this list -- Replaces, does not merge: a configuration with a higher priority replaces this list
-- completely, so providers trusted by the base configuration lose that status. Repeat -- completely, so providers trusted by the base configuration lose that status. Repeat

View File

@ -125,8 +125,6 @@ public static class DataSourceSecurityTrustExtensions
public static bool IsTrustedByConfiguration(this TranscriptionProvider provider, SettingsManager settingsManager) => IsTrustedProviderId(provider.Id, settingsManager); public static bool IsTrustedByConfiguration(this TranscriptionProvider provider, SettingsManager settingsManager) => IsTrustedProviderId(provider.Id, settingsManager);
public static bool IsTrustedByConfiguration(this IProvider provider, SettingsManager settingsManager) => IsTrustedProviderId(provider.ConfiguredProviderId, settingsManager);
private static bool IsTrustedProviderId(string providerId, SettingsManager settingsManager) private static bool IsTrustedProviderId(string providerId, SettingsManager settingsManager)
{ {
if (string.IsNullOrWhiteSpace(providerId)) if (string.IsNullOrWhiteSpace(providerId))

View File

@ -28,9 +28,9 @@ public sealed class ConfluenceSearchTool(WebPageRetrievalService webPageRetrieva
{ {
Id = ToolSelectionRules.SEARCH_CONFLUENCE_TOOL_ID, Id = ToolSelectionRules.SEARCH_CONFLUENCE_TOOL_ID,
ImplementationKey = ToolSelectionRules.SEARCH_CONFLUENCE_TOOL_ID, ImplementationKey = ToolSelectionRules.SEARCH_CONFLUENCE_TOOL_ID,
// Kept low so that providers trusted by the organization below HIGH are offered the tool. // Every search result is internal to the organization and raises the chat's required
// The runtime check in ExecuteAsync requires HIGH confidence or that trust. // confidence to HIGH, so only providers which may continue the chat are offered the tool:
MinimumProviderConfidence = ConfidenceLevel.VERY_LOW, MinimumProviderConfidence = ConfidenceLevel.HIGH,
SettingsSchema = ToolSettingsSchemaBuilder.Create() SettingsSchema = ToolSettingsSchemaBuilder.Create()
.Required(BASE_URL_SETTING) .Required(BASE_URL_SETTING)
.Optional(TIMEOUT_SECONDS_SETTING) .Optional(TIMEOUT_SECONDS_SETTING)
@ -96,12 +96,12 @@ public sealed class ConfluenceSearchTool(WebPageRetrievalService webPageRetrieva
public async Task<ToolExecutionResult> ExecuteAsync(JsonElement arguments, ToolExecutionContext context, CancellationToken token = default) public async Task<ToolExecutionResult> ExecuteAsync(JsonElement arguments, ToolExecutionContext context, CancellationToken token = default)
{ {
// //
// A provider trusted by the organization's configuration counts as much as a High-confidence // The tool settings may lower the level at which the tool is offered, but what the wiki
// one. The chat thread's own check does the same, so such a provider may also continue the // returns stays internal to the organization. The search itself therefore always needs
// chat after the result raised its required confidence to HIGH. // a High-confidence provider.
// //
if (context.ProviderConfidence < ConfidenceLevel.HIGH && !context.ProviderIsTrustedByConfiguration) if (context.ProviderConfidence < ConfidenceLevel.HIGH)
throw new ToolExecutionBlockedException(TB("Searching the company wiki requires a High-confidence provider or one trusted by your organization's configuration.")); throw new ToolExecutionBlockedException(TB("Searching your company's wiki requires a High-confidence provider."));
if (!TryParseBaseUrl(context.SettingsValues.GetValueOrDefault(BASE_URL_SETTING), out var baseUrl)) if (!TryParseBaseUrl(context.SettingsValues.GetValueOrDefault(BASE_URL_SETTING), out var baseUrl))
throw new InvalidOperationException(TB("The Confluence base URL is not configured correctly.")); throw new InvalidOperationException(TB("The Confluence base URL is not configured correctly."));
@ -136,7 +136,6 @@ public sealed class ConfluenceSearchTool(WebPageRetrievalService webPageRetrieva
{ {
TimeoutSeconds = timeoutSeconds, TimeoutSeconds = timeoutSeconds,
ProviderConfidence = context.ProviderConfidence, ProviderConfidence = context.ProviderConfidence,
ProviderIsTrustedByConfiguration = context.ProviderIsTrustedByConfiguration,
UseOsSso = true, UseOsSso = true,
IsPrivateHostAllowed = host => IsWikiHost(baseUrl!, host), IsPrivateHostAllowed = host => IsWikiHost(baseUrl!, host),

View File

@ -73,7 +73,7 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ
{ {
TIMEOUT_SECONDS_SETTING => TB("(Optional) HTTP timeout for loading a web page in seconds."), 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."), 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 or a provider trusted by your organization's configuration. For allowed HTTPS internal hosts, AI Studio also tries the operating system's default sign-in automatically when the server responds with integrated authentication."), 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."),
_ => TB(fieldDefinition.Description), _ => TB(fieldDefinition.Description),
}; };
@ -144,7 +144,6 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ
{ {
TimeoutSeconds = timeoutSeconds, TimeoutSeconds = timeoutSeconds,
ProviderConfidence = context.ProviderConfidence, ProviderConfidence = context.ProviderConfidence,
ProviderIsTrustedByConfiguration = context.ProviderIsTrustedByConfiguration,
UseOsSso = true, UseOsSso = true,
IsPrivateHostAllowed = host => IsAllowedPrivateHost(host, allowedPrivateHosts), IsPrivateHostAllowed = host => IsAllowedPrivateHost(host, allowedPrivateHosts),
OnPrivateHostProviderBlockAsync = this.ReportPrivateHostProviderBlockAsync, OnPrivateHostProviderBlockAsync = this.ReportPrivateHostProviderBlockAsync,
@ -275,13 +274,13 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ
private async Task ReportPrivateHostProviderBlockAsync(Uri url, ConfidenceLevel providerConfidence) private async Task ReportPrivateHostProviderBlockAsync(Uri url, ConfidenceLevel providerConfidence)
{ {
logger.LogWarning( logger.LogWarning(
"Blocked read_web_page access to allowed private host '{Host}' because provider confidence '{ProviderConfidence}' is below HIGH and the provider is not trusted by configuration.", "Blocked read_web_page access to allowed private host '{Host}' because provider confidence '{ProviderConfidence}' is below HIGH.",
url.Host, url.Host,
providerConfidence); providerConfidence);
await MessageBus.INSTANCE.SendError(new DataErrorMessage( await MessageBus.INSTANCE.SendError(new DataErrorMessage(
Icons.Material.Filled.Security, Icons.Material.Filled.Security,
TB("The web page was not loaded because private or VPN web pages require a High-confidence provider or a provider trusted by your organization's configuration."))); TB("The web page was not loaded because private or VPN web pages require a High-confidence provider.")));
} }
private static bool IsAllowedPrivateHost(string host, IReadOnlyList<AllowedPrivateHostPattern> allowedPrivateHosts) private static bool IsAllowedPrivateHost(string host, IReadOnlyList<AllowedPrivateHostPattern> allowedPrivateHosts)

View File

@ -14,6 +14,4 @@ public sealed class ToolExecutionContext
public required IReadOnlyDictionary<string, string> SettingsValues { get; init; } public required IReadOnlyDictionary<string, string> SettingsValues { get; init; }
public ConfidenceLevel ProviderConfidence { get; init; } = ConfidenceLevel.UNKNOWN; public ConfidenceLevel ProviderConfidence { get; init; } = ConfidenceLevel.UNKNOWN;
public bool ProviderIsTrustedByConfiguration { get; init; }
} }

View File

@ -109,7 +109,6 @@ public sealed class ToolExecutor(ToolSettingsService toolSettingsService, ILogge
SettingsManager = settingsManager, SettingsManager = settingsManager,
SettingsValues = settingsValues, SettingsValues = settingsValues,
ProviderConfidence = provider.Provider.GetConfidence(settingsManager).Level, ProviderConfidence = provider.Provider.GetConfidence(settingsManager).Level,
ProviderIsTrustedByConfiguration = provider.IsTrustedByConfiguration(settingsManager),
}, token); }, token);
logger.LogInformation("Completed tool execution. ToolName={ToolName}, ToolCallId={ToolCallId}, DurationMs={DurationMs}, Status={Status}", toolName, toolCallId, stopwatch.ElapsedMilliseconds, ToolInvocationTraceStatus.SUCCESS); logger.LogInformation("Completed tool execution. ToolName={ToolName}, ToolCallId={ToolCallId}, DurationMs={DurationMs}, Status={Status}", toolName, toolCallId, stopwatch.ElapsedMilliseconds, ToolInvocationTraceStatus.SUCCESS);

View File

@ -24,8 +24,6 @@ public sealed class WebPageRetrievalOptions
public ConfidenceLevel ProviderConfidence { get; init; } = ConfidenceLevel.NONE; public ConfidenceLevel ProviderConfidence { get; init; } = ConfidenceLevel.NONE;
public bool ProviderIsTrustedByConfiguration { get; init; }
public bool UseOsSso { get; init; } public bool UseOsSso { get; init; }
public Func<string, bool>? IsPrivateHostAllowed { get; init; } public Func<string, bool>? IsPrivateHostAllowed { get; init; }

View File

@ -124,12 +124,12 @@ public sealed class WebPageRetrievalService(HTMLParser htmlParser)
if (options.PublicTargetsOnly || options.IsPrivateHostAllowed?.Invoke(url.Host) is not true) if (options.PublicTargetsOnly || options.IsPrivateHostAllowed?.Invoke(url.Host) is not true)
throw new WebPageAccessBlockedException("Private or local-network web page URLs are not supported unless their host is explicitly allowed.", WebPageAccessBlockReason.PRIVATE_HOST_NOT_ALLOWED); throw new WebPageAccessBlockedException("Private or local-network web page URLs are not supported unless their host is explicitly allowed.", WebPageAccessBlockReason.PRIVATE_HOST_NOT_ALLOWED);
if (options.ProviderConfidence >= ConfidenceLevel.HIGH || options.ProviderIsTrustedByConfiguration) if (options.ProviderConfidence >= ConfidenceLevel.HIGH)
return addresses; return addresses;
if (options.OnPrivateHostProviderBlockAsync is not null) if (options.OnPrivateHostProviderBlockAsync is not null)
await options.OnPrivateHostProviderBlockAsync(url, options.ProviderConfidence); await options.OnPrivateHostProviderBlockAsync(url, options.ProviderConfidence);
throw new WebPageAccessBlockedException("This private or VPN web page requires a High-confidence provider or a provider trusted by configuration.", WebPageAccessBlockReason.INSUFFICIENT_PROVIDER_CONFIDENCE); throw new WebPageAccessBlockedException("This private or VPN web page requires a High-confidence provider.", WebPageAccessBlockReason.INSUFFICIENT_PROVIDER_CONFIDENCE);
} }
private static async Task<IReadOnlyList<IPAddress>> ResolveHostAddressesAsync(Uri url, CancellationToken token) private static async Task<IReadOnlyList<IPAddress>> ResolveHostAddressesAsync(Uri url, CancellationToken token)
@ -154,8 +154,7 @@ public sealed class WebPageRetrievalService(HTMLParser htmlParser)
Uri candidateUrl, Uri candidateUrl,
IReadOnlyList<IPAddress> addresses, IReadOnlyList<IPAddress> addresses,
WebPageRetrievalOptions options) => WebPageRetrievalOptions options) =>
options.UseOsSso && options is { UseOsSso: true, ProviderConfidence: >= ConfidenceLevel.HIGH } &&
(options.ProviderConfidence >= ConfidenceLevel.HIGH || options.ProviderIsTrustedByConfiguration) &&
candidateUrl.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) && candidateUrl.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) &&
originalUrl.Scheme.Equals(candidateUrl.Scheme, StringComparison.OrdinalIgnoreCase) && originalUrl.Scheme.Equals(candidateUrl.Scheme, StringComparison.OrdinalIgnoreCase) &&
originalUrl.Host.Equals(candidateUrl.Host, StringComparison.OrdinalIgnoreCase) && originalUrl.Host.Equals(candidateUrl.Host, StringComparison.OrdinalIgnoreCase) &&

View File

@ -4,7 +4,7 @@
- Added a way to save a single code block of an answer. When an answer holds a web page, a LaTeX document, or a Markdown text, the export menu now offers that block as a file of its own. - Added a way to save a single code block of an answer. When an answer holds a web page, a LaTeX document, or a Markdown text, the export menu now offers that block as a file of its own.
- Added a Search Confluence tool for your company's wiki. Set your wiki's address in the tool settings, then select the tool alongside Read Web Page so the AI can find relevant pages and open them. The Confluence logo shows you the tool in tool lists and in your chat's tool activity. - Added a Search Confluence tool for your company's wiki. Set your wiki's address in the tool settings, then select the tool alongside Read Web Page so the AI can find relevant pages and open them. The Confluence logo shows you the tool in tool lists and in your chat's tool activity.
- Added sign-in with your operating system account to the Search Confluence tool, so you do not have to enter a password. When your wiki does not accept that sign-in, AI Studio tells you so instead of reporting an empty search. - Added sign-in with your operating system account to the Search Confluence tool, so you do not have to enter a password. When your wiki does not accept that sign-in, AI Studio tells you so instead of reporting an empty search.
- Added safeguards to the Search Confluence tool: it works only with a High-confidence provider or one your organization trusts, and it never follows a redirect that leads away from your wiki. Each search appears in the sources of the answer. - Added safeguards to the Search Confluence tool: it works only with a High-confidence provider, and it never follows a redirect that leads away from your wiki. Each search appears in the sources of the answer.
- Added tools that AI models can use on their own, starting with Web Search and Read Web Page. When you ask something a model cannot answer from what it knows, it now searches the web, reads the pages it found, and answers with the sources it used. You decide which tools a model may use, right below the message field, and you can watch it work: AI Studio shows which tool is running and, afterward, every call it made with its result. Whether tools are offered at all depends on the model because it has to support them. Read Web Page works right away; for Web Search you pick a search service in the app settings — Tavily or Staan with a free API key, or a SearXNG instance you run yourself. Set up more than one, and they can take turns when one of them finds nothing, or be asked all at once with their results combined. Many thanks to Peer Hogeterp (`peerschuett`) and Nils Kruthoff (`nilskruthoff`) for building this feature. - Added tools that AI models can use on their own, starting with Web Search and Read Web Page. When you ask something a model cannot answer from what it knows, it now searches the web, reads the pages it found, and answers with the sources it used. You decide which tools a model may use, right below the message field, and you can watch it work: AI Studio shows which tool is running and, afterward, every call it made with its result. Whether tools are offered at all depends on the model because it has to support them. Read Web Page works right away; for Web Search you pick a search service in the app settings — Tavily or Staan with a free API key, or a SearXNG instance you run yourself. Set up more than one, and they can take turns when one of them finds nothing, or be asked all at once with their results combined. Many thanks to Peer Hogeterp (`peerschuett`) and Nils Kruthoff (`nilskruthoff`) for building this feature.
- Added answers that appear word by word even while the AI uses its tools. You read along as the model writes, including the short note it puts down before it looks something up, and the answer that follows a tool call arrives the same way instead of all at once at the end. - Added answers that appear word by word even while the AI uses its tools. You read along as the model writes, including the short note it puts down before it looks something up, and the answer that follows a tool call arrives the same way instead of all at once at the end.
- Added safeguards around everything these tools bring back. Anything fetched from the web is treated as untrusted: AI Studio removes instructions hidden in a page before a model reads it and tells you when it did, exactly as it already does for the documents and web pages you load yourself. A model can never point a tool at your own network. Each tool states how much you have to trust a provider before it may be used with it, so your questions do not travel further than you allow. You can adjust that requirement per tool in the app settings. - Added safeguards around everything these tools bring back. Anything fetched from the web is treated as untrusted: AI Studio removes instructions hidden in a page before a model reads it and tells you when it did, exactly as it already does for the documents and web pages you load yourself. A model can never point a tool at your own network. Each tool states how much you have to trust a provider before it may be used with it, so your questions do not travel further than you allow. You can adjust that requirement per tool in the app settings.
@ -55,8 +55,7 @@
- Improved the file name AI Studio suggests when you export an answer. Instead of always proposing "export", it now suggests the name of your chat or of the assistant you are working in. In the Document Analysis assistant, it suggests the name of the policy. - Improved the file name AI Studio suggests when you export an answer. Instead of always proposing "export", it now suggests the name of your chat or of the assistant you are working in. In the Document Analysis assistant, it suggests the name of the policy.
- Changed what a tile that opens a chat directly starts with: when it uses a chat template that brings its own tools or data sources, that template decides them. The Assistant Builder says so while you build such a tile. - Changed what a tile that opens a chat directly starts with: when it uses a chat template that brings its own tools or data sources, that template decides them. The Assistant Builder says so while you build such a tile.
- Changed which model a security check of an assistant plugin may fall back on. When you have set none aside for these checks, AI Studio uses the model you were working with, but only when that model meets the trust your organization requires for a check. One ruled out for that purpose no longer gets to read a plugin's code. - Changed which model a security check of an assistant plugin may fall back on. When you have set none aside for these checks, AI Studio uses the model you were working with, but only when that model meets the trust your organization requires for a check. One ruled out for that purpose no longer gets to read a plugin's code.
- Changed how provider trust and provider confidence work together for local data sources. Marking a provider as trustworthy in a configuration no longer also satisfies the confidence level a data source requires: one says who runs the provider, the other how confidential it is. Organizations raise a provider's level in their own confidence scheme instead. - Changed how provider trust and provider confidence work together. Marking a provider as trustworthy in a configuration no longer also satisfies a required confidence level: one says who runs the provider, the other how confidential it is. Organizations raise a provider's level in their own confidence scheme instead. This applies beyond local data sources, for example, when a model reads a page from your intranet.
- Changed which providers may continue a chat that holds confidential tool results, for example a page from your intranet or a search in your company wiki. A provider your organization marked as trustworthy in its configuration may continue such a chat, just as it may use the tools which brought those results in.
- Fixed the abilities AI Studio assumed for many models. We checked the families against their documentation: some models gained image input, reasoning, or tool calling, others lost an ability they never had. - Fixed the abilities AI Studio assumed for many models. We checked the families against their documentation: some models gained image input, reasoning, or tool calling, others lost an ability they never had.
- Fixed the Document Analysis assistant freezing while you edited a policy. It needed a change of yours to be saved in the background just as you were making the next one — picking a provider, for instance — which is why it hit some of you again and again and others never at all. - Fixed the Document Analysis assistant freezing while you edited a policy. It needed a change of yours to be saved in the background just as you were making the next one — picking a provider, for instance — which is why it hit some of you again and again and others never at all.
- Fixed a renamed policy losing its new name in the Document Analysis assistant. The name was kept only when you happened to change something else afterward. - Fixed a renamed policy losing its new name in the Document Analysis assistant. The name was kept only when you happened to change something else afterward.

View File

@ -54,7 +54,7 @@ Keep `Function.DescriptionForLLM` focused on what the tool does. This value is m
A setting offering a fixed choice takes it from an option source — `RequiredChoice` and `OptionalChoice` name a list the app maintains, see `ToolSettingsOptionSources` — or spells its values out in the field's `enum` list, which is how a definition arriving as data offers a choice of its own. The two are mutually exclusive, and `ToolRegistry` rejects a definition that uses both or names an unknown source. Check a stored value in `ValidateConfigurationAsync` either way: it can predate the current list or arrive from an organization's configuration. A setting offering a fixed choice takes it from an option source — `RequiredChoice` and `OptionalChoice` name a list the app maintains, see `ToolSettingsOptionSources` — or spells its values out in the field's `enum` list, which is how a definition arriving as data offers a choice of its own. The two are mutually exclusive, and `ToolRegistry` rejects a definition that uses both or names an unknown source. Check a stored value in `ValidateConfigurationAsync` either way: it can predate the current list or arrive from an organization's configuration.
When a tool returns data that future messages must only send to providers at or above a specific confidence level, set `ToolExecutionResult.RequiredProviderConfidence`. AI Studio persists the highest requirement reached by the chat and applies it to later provider checks. Provider instances listed in `DataSourceSecuritySettings.TrustedProviderIds` may also continue chats containing data protected this way. When a tool returns data that future messages must only send to providers at or above a specific confidence level, set `ToolExecutionResult.RequiredProviderConfidence`. AI Studio persists the highest requirement reached by the chat and applies it to later provider checks. Being listed in `DataSourceSecuritySettings.TrustedProviderIds` does not meet that requirement: the list belongs to data-source security checks, not to confidence. An organization which wants a contractually covered provider to continue such chats raises its level through `DataConfidence.CustomConfidenceScheme`.
## Security ## Security
@ -88,11 +88,11 @@ The prompt-level warning in `systemPromptInstructions` — that everything a too
`web_search` and `read_web_page` both load pages, and so does the `ReadWebContent` component the assistants offer. All three go through `WebPageRetrievalService` — every page AI Studio reads goes through that one service. It validates DNS results and every redirect target before connecting, binds the connection to the validated addresses, caps the response size, and accepts only HTML. `web_search` and `read_web_page` both load pages, and so does the `ReadWebContent` component the assistants offer. All three go through `WebPageRetrievalService` — every page AI Studio reads goes through that one service. It validates DNS results and every redirect target before connecting, binds the connection to the validated addresses, caps the response size, and accepts only HTML.
What differs between callers is which targets are acceptable, and that follows from who chose the URL. `web_search` uses the public-only policy and never reads private, loopback, or link-local targets. `read_web_page` may reach an explicitly allowed private host, and only for a High-confidence or configuration-trusted provider. The `ReadWebContent` component sets `TargetChosenByUser`, which lifts the target restrictions entirely: the user typed the address, so their own network and a local server are legitimate. Never set that flag for a URL that reached AI Studio through a model. What differs between callers is which targets are acceptable, and that follows from who chose the URL. `web_search` uses the public-only policy and never reads private, loopback, or link-local targets. `read_web_page` may reach an explicitly allowed private host, and only for a High-confidence provider. The `ReadWebContent` component sets `TargetChosenByUser`, which lifts the target restrictions entirely: the user typed the address, so their own network and a local server are legitimate. Never set that flag for a URL that reached AI Studio through a model.
`read_web_page` remains the independent single-URL tool and may use its configured private-host allowlist and operating-system sign-in behavior for allowed HTTPS targets. An allowed private host can only be read by a High-confidence provider or a provider instance listed in `DataSourceSecuritySettings.TrustedProviderIds`. `read_web_page` remains the independent single-URL tool and may use its configured private-host allowlist and operating-system sign-in behavior for allowed HTTPS targets. An allowed private host can only be read by a High-confidence provider.
`search_confluence` builds a CQL query for the configured HTTPS Confluence Data Center site's `dosearchsite.action` page and loads it through `WebPageRetrievalService`, the same reader used by `read_web_page`. The model supplies a search phrase and optionally a space key, never a URL or CQL expression. The tool returns the extracted search page as Markdown with links, after truncation and prompt-injection filtering, and lists the search page as its source. Every request, redirects included, must stay within the configured base URL; `WebPageRetrievalOptions.IsTargetAllowed` refuses a redirect before it is followed, so the query never reaches another host. The operating-system sign-in goes to the configured host even when it has public addresses (`IsOsSsoAllowedForPublicHost`), and a redirect to Confluence's login page is reported as a failed sign-in instead of an empty search. The tool treats a provider trusted by the organization the same as a High-confidence one, and the result raises the chat's continuing confidence requirement to High. `ChatThreadExtensions.IsLLMProviderAllowed` lets a trusted provider meet that requirement as well, so it can continue the chat after a search. Selecting `search_confluence` also selects `read_web_page` so the model can load a result's full content; the latter tool's private-host allowlist and other availability rules still apply. `search_confluence` builds a CQL query for the configured HTTPS Confluence Data Center site's `dosearchsite.action` page and loads it through `WebPageRetrievalService`, the same reader used by `read_web_page`. The model supplies a search phrase and optionally a space key, never a URL or CQL expression. The tool returns the extracted search page as Markdown with links, after truncation and prompt-injection filtering, and lists the search page as its source. Every request, redirects included, must stay within the configured base URL; `WebPageRetrievalOptions.IsTargetAllowed` refuses a redirect before it is followed, so the query never reaches another host. The operating-system sign-in goes to the configured host even when it has public addresses (`IsOsSsoAllowedForPublicHost`), and a redirect to Confluence's login page is reported as a failed sign-in instead of an empty search. The tool is offered to High-confidence providers only and checks that again before each search, because a lowered tool setting must not let internal wiki content reach a less trusted provider; the result raises the chat's continuing confidence requirement to High. Selecting `search_confluence` also selects `read_web_page` so the model can load a result's full content; the latter tool's private-host allowlist and other availability rules still apply.
Every successfully retrieved page with readable content is also returned as a structured tool source, using the final URL after redirects and the extracted page title. The provider collects these sources across local tool calls and attaches them to the final response under the separate “Sources used by tools” heading. Failed, blocked, empty, and duplicate retrievals do not add sources — a pattern worth copying for any tool that returns material the user may want to check. Every successfully retrieved page with readable content is also returned as a structured tool source, using the final URL after redirects and the extracted page title. The provider collects these sources across local tool calls and attaches them to the final response under the separate “Sources used by tools” heading. Failed, blocked, empty, and duplicate retrievals do not add sources — a pattern worth copying for any tool that returns material the user may want to check.