diff --git a/chrome/browser/ai/ai_language_model.cc b/chrome/browser/ai/ai_language_model.cc index a35583d2e4e2d..9a715f6bf9649 100644 --- a/chrome/browser/ai/ai_language_model.cc +++ b/chrome/browser/ai/ai_language_model.cc @@ -159,6 +159,9 @@ on_device_model::mojom::InputPtr ConvertToInput( // TODO(crbug.com/422803232): Support on_device_model tool use. return nullptr; case blink::mojom::AILanguageModelPromptContent::Tag::kToolResponse: { + if (!capabilities.Has(on_device_model::CapabilityFlags::kToolUse)) { + return nullptr; + } // TODO(crbug.com/422803232): Support image/audio result types. auto response = GetToolResponseFromDict(content->get_tool_response()); if (!response) { diff --git a/chrome/browser/ai/ai_manager.cc b/chrome/browser/ai/ai_manager.cc index 440c485e903ca..32744a016e259 100644 --- a/chrome/browser/ai/ai_manager.cc +++ b/chrome/browser/ai/ai_manager.cc @@ -688,9 +688,15 @@ void AIManager::CanCreateLanguageModel( kUnavailableModelAdaptationNotAvailable); return; } - // Note: Tool use capabilities are gated by RuntimeEnabledFeatures in Blink. // Tool use capability is signaled by the presence of tool declarations. if (options->tools.has_value() && !options->tools->empty()) { + // Browser-side re-validation of the renderer-only RuntimeEnabledFeatures + // gate; do not trust the renderer to have enforced it. + if (!base::FeatureList::IsEnabled(blink::features::kAIPromptAPIToolUse)) { + std::move(callback).Run(blink::mojom::ModelAvailabilityCheckResult:: + kUnavailableModelAdaptationNotAvailable); + return; + } input_capabilities.Put(on_device_model::CapabilityFlags::kToolUse); } } @@ -846,11 +852,16 @@ void AIManager::CreateLanguageModelInternal( return; } if (!params->capabilities.empty()) { - // Check if multimodal input (image/audio) is used without the feature flag - // or if the model doesn't support the requested capabilities. + // Check if multimodal input (image/audio) is used without the feature flag, + // tool use is requested without the feature flag, or the model doesn't + // support the requested capabilities. Do not trust the renderer to have + // enforced the matching RuntimeEnabledFeatures gates. if ((HasMultimodalInputCapabilities(params->capabilities) && !base::FeatureList::IsEnabled( blink::features::kAIPromptAPIMultimodalInput)) || + (params->capabilities.Has(on_device_model::CapabilityFlags::kToolUse) && + !base::FeatureList::IsEnabled( + blink::features::kAIPromptAPIToolUse)) || !model_client->capabilities().HasAll(params->capabilities)) { mojo::Remote client_remote(std::move(client));