+
loadTimeData.getBoolean(
'isLeoAssistantHistoryAllowed')
},
+ isTabOrganizationFeatureEnabled_: {
+ type: Boolean,
+ value: () => loadTimeData.getBoolean(
+ 'isTabOrganizationFeatureEnabled')
+ },
}
}
private declare isPremiumUser_: boolean
declare isHistoryFeatureEnabled_: boolean
- declare selectedModelDisplayName_: string
+ declare isTabOrganizationFeatureEnabled_: boolean
declare defaultModelKeyPrefValue_: string
declare models_: ModelWithSubtitle[]
premiumStatus_: PremiumStatus = PremiumStatus.Unknown
@@ -130,21 +128,10 @@ class BraveLeoPersonalization extends BraveLeoPersonalizationBase {
})
}
- computeDisplayName_() {
- const foundEntry = this.models_?.find(
- (entry) => {
- return entry.model.key === this.defaultModelKeyPrefValue_
- }
- )
-
- return foundEntry?.model.displayName
- }
-
onModelSelectionChange_(e: any) {
- this.browserProxy_.getSettingsHelper().setDefaultModelKey(e.value)
+ this.browserProxy_.getSettingsHelper().setDefaultModelKey(e.detail.value)
}
-
private updateCurrentPremiumStatus() {
this.browserProxy_.getSettingsHelper().getPremiumStatus()
.then((value: { status: PremiumStatus; info: PremiumInfo | null; }) => {
@@ -152,10 +139,6 @@ class BraveLeoPersonalization extends BraveLeoPersonalizationBase {
})
}
- private isLeoModel_(model: Model) {
- return model.options.leoModelOptions !== undefined
- }
-
computeIsPremiumUser_() {
if (this.premiumStatus_ === PremiumStatus.Active ||
this.premiumStatus_ === PremiumStatus.ActiveDisconnected) {
@@ -165,10 +148,6 @@ class BraveLeoPersonalization extends BraveLeoPersonalizationBase {
return false
}
- shouldShowModelPremiumLabel_(modelAccess: ModelAccess) {
- return (modelAccess === ModelAccess.PREMIUM && !this.isPremiumUser_)
- }
-
private onStorageEnabledChange_(event: Event) {
const target = event.target
assert(target instanceof SettingsToggleButtonElement);
@@ -185,6 +164,18 @@ class BraveLeoPersonalization extends BraveLeoPersonalizationBase {
const router = Router.getInstance();
router.navigateTo(router.getRoutes().BRAVE_LEO_CUSTOMIZATION);
}
+
+ private onTabOrganizationModelChange_(e: any) {
+ this.setPrefValue(
+ 'brave.ai_chat.tab_organization_model_key',
+ e.detail.value)
+ }
+
+ private isTabOrganizationDropdownVisible_(
+ featureEnabled: boolean,
+ prefEnabled: boolean) {
+ return featureEnabled && prefEnabled
+ }
}
customElements.define(BraveLeoPersonalization.is, BraveLeoPersonalization)
diff --git a/browser/resources/settings/sources.gni b/browser/resources/settings/sources.gni
index 16369e3a3fe..72755b6c024 100644
--- a/browser/resources/settings/sources.gni
+++ b/browser/resources/settings/sources.gni
@@ -195,8 +195,13 @@ if (enable_ai_chat) {
"brave_leo_assistant_page/model_config_ui.ts",
"brave_leo_assistant_page/personalization.ts",
]
- brave_settings_ts_files +=
- [ "brave_leo_assistant_page/brave_leo_assistant_browser_proxy.ts" ]
+ brave_settings_ts_files += [
+ "brave_leo_assistant_page/brave_leo_assistant_browser_proxy.ts",
+ "brave_leo_assistant_page/model_selector.html.ts",
+ "brave_leo_assistant_page/model_selector.ts",
+ ]
+ brave_settings_local_css_files +=
+ [ "brave_leo_assistant_page/model_selector.css" ]
}
brave_settings_ts_definitions =
diff --git a/browser/ui/webui/settings/brave_settings_localized_strings_provider.cc b/browser/ui/webui/settings/brave_settings_localized_strings_provider.cc
index ae362fc7c94..83bb365191a 100644
--- a/browser/ui/webui/settings/brave_settings_localized_strings_provider.cc
+++ b/browser/ui/webui/settings/brave_settings_localized_strings_provider.cc
@@ -54,6 +54,7 @@
#if BUILDFLAG(ENABLE_AI_CHAT)
#include "brave/components/ai_chat/core/browser/model_validator.h"
+#include "brave/components/ai_chat/core/common/features.h"
#endif
#if BUILDFLAG(ENABLE_TOR)
@@ -564,6 +565,8 @@ void BraveAddCommonStrings(content::WebUIDataSource* html_source,
IDS_SETTINGS_LEO_ASSISTANT_SHOW_IN_CONTEXT_MENU_DESC},
{"braveLeoAssistantTabOrganizationLabel",
IDS_SETTINGS_LEO_ASSISTANT_TAB_ORGANIZATION_LABEL},
+ {"braveLeoAssistantTabOrganizationModelLabel",
+ IDS_SETTINGS_LEO_ASSISTANT_TAB_ORGANIZATION_MODEL_LABEL},
{"braveLeoAssistantHistoryPreferenceLabel",
IDS_SETTINGS_LEO_ASSISTANT_HISTORY_PREFERENCE_LABEL},
{"braveLeoAssistantHistoryPreferenceConfirm",
@@ -1100,6 +1103,9 @@ void BraveAddCommonStrings(content::WebUIDataSource* html_source,
html_source->AddString("braveLeoAssistantTabOrganizationLearnMoreURL",
kTabOrganizationLearnMoreURL);
+
+ html_source->AddBoolean("isTabOrganizationFeatureEnabled",
+ ai_chat::features::IsTabOrganizationEnabled());
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/components/ai_chat/core/browser/ai_chat_service.cc b/components/ai_chat/core/browser/ai_chat_service.cc
index 9b11e8fbf7b..b6aabed4587 100644
--- a/components/ai_chat/core/browser/ai_chat_service.cc
+++ b/components/ai_chat/core/browser/ai_chat_service.cc
@@ -158,6 +158,10 @@ AIChatService::AIChatService(
prefs::kBraveAIChatSkills,
base::BindRepeating(&AIChatService::OnSkillsChanged,
weak_ptr_factory_.GetWeakPtr()));
+ pref_change_registrar_.Add(
+ prefs::kBraveAIChatTabOrganizationModelKey,
+ base::BindRepeating(&AIChatService::OnTabOrganizationModelPrefChanged,
+ weak_ptr_factory_.GetWeakPtr()));
MaybeInitStorage();
@@ -1314,9 +1318,20 @@ AIChatService::CreateToolProvidersForNewConversation() {
}
void AIChatService::CreateTabOrganizationEngineIfNeeded() {
- if (!tab_organization_engine_) {
- tab_organization_engine_ = GetEngineForModel(kChatAutomaticModelKey);
+ if (tab_organization_engine_) {
+ return;
}
+
+ std::string target_key =
+ profile_prefs_->GetString(prefs::kBraveAIChatTabOrganizationModelKey);
+ if (!model_service_->GetModel(target_key)) {
+ target_key = kChatAutomaticModelKey;
+ }
+ tab_organization_engine_ = GetEngineForModel(target_key);
+}
+
+void AIChatService::OnTabOrganizationModelPrefChanged() {
+ tab_organization_engine_.reset();
}
void AIChatService::OnSuggestedTopicsReceived(
diff --git a/components/ai_chat/core/browser/ai_chat_service.h b/components/ai_chat/core/browser/ai_chat_service.h
index 5dbdb6d26c3..bc238113402 100644
--- a/components/ai_chat/core/browser/ai_chat_service.h
+++ b/components/ai_chat/core/browser/ai_chat_service.h
@@ -18,6 +18,7 @@
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
+#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
@@ -248,6 +249,8 @@ class AIChatService : public KeyedService,
private:
friend class AIChatServiceUnitTest;
+ FRIEND_TEST_ALL_PREFIXES(AIChatServiceUnitTest,
+ CreateTabOrganizationEngineIfNeeded_InvalidModelKey);
// Key is uuid
using ConversationMap =
@@ -318,6 +321,7 @@ class AIChatService : public KeyedService,
void InitializeTools();
void CreateTabOrganizationEngineIfNeeded();
+ void OnTabOrganizationModelPrefChanged();
void OnSuggestedTopicsReceived(
GetSuggestedTopicsCallback callback,
diff --git a/components/ai_chat/core/browser/ai_chat_service_unittest.cc b/components/ai_chat/core/browser/ai_chat_service_unittest.cc
index 8eb041cbbec..66c6a8300ce 100644
--- a/components/ai_chat/core/browser/ai_chat_service_unittest.cc
+++ b/components/ai_chat/core/browser/ai_chat_service_unittest.cc
@@ -47,6 +47,7 @@
#include "brave/components/ai_chat/core/browser/test_utils.h"
#include "brave/components/ai_chat/core/browser/tools/memory_storage_tool.h"
#include "brave/components/ai_chat/core/browser/tools/tool.h"
+#include "brave/components/ai_chat/core/browser/types.h"
#include "brave/components/ai_chat/core/browser/utils.h"
#include "brave/components/ai_chat/core/common/features.h"
#include "brave/components/ai_chat/core/common/mojom/ai_chat.mojom.h"
@@ -67,6 +68,7 @@
#include "third_party/abseil-cpp/absl/strings/str_format.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
+#include "url/origin.h"
using ::testing::_;
using ::testing::Eq;
@@ -1374,6 +1376,22 @@ TEST_P(AIChatServiceUnitTest, GetFocusTabs_EmptyTabs) {
run_loop.Run();
}
+TEST_P(AIChatServiceUnitTest,
+ CreateTabOrganizationEngineIfNeeded_InvalidModelKey) {
+ // Set the pref to a key that doesn't resolve to any valid model.
+ prefs_.SetString(prefs::kBraveAIChatTabOrganizationModelKey,
+ "nonexistent-model");
+
+ // Call CreateTabOrganizationEngineIfNeeded directly to verify the fallback
+ // logic without triggering the full request flow.
+ ai_chat_service_->CreateTabOrganizationEngineIfNeeded();
+
+ auto* engine = ai_chat_service_->GetTabOrganizationEngineForTesting();
+ ASSERT_NE(engine, nullptr);
+
+ EXPECT_EQ(engine->GetModelName(), "automatic");
+}
+
TEST_P(AIChatServiceUnitTest, TemporaryConversation_NoDatabaseInteraction) {
// We create mock DB object regardless of whether history is enabled.
// In real case, there's no DB object at all if history is disabled, this
diff --git a/components/ai_chat/core/common/pref_names.cc b/components/ai_chat/core/common/pref_names.cc
index 11816f5393d..6781befb4ff 100644
--- a/components/ai_chat/core/common/pref_names.cc
+++ b/components/ai_chat/core/common/pref_names.cc
@@ -8,6 +8,7 @@
#include
#include "base/time/time.h"
+#include "brave/components/ai_chat/core/common/constants.h"
#include "brave/components/ai_chat/core/common/features.h"
#include "components/prefs/pref_registry_simple.h"
@@ -39,6 +40,8 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kBraveAIChatToolbarButtonOpensFullPage,
false);
registry->RegisterBooleanPref(kBraveAIChatTabOrganizationEnabled, true);
+ registry->RegisterStringPref(kBraveAIChatTabOrganizationModelKey,
+ kChatAutomaticModelKey);
registry->RegisterBooleanPref(kBraveAIChatUserCustomizationEnabled, true);
registry->RegisterBooleanPref(kBraveAIChatUserMemoryEnabled, true);
registry->RegisterDictionaryPref(kBraveAIChatUserCustomizations);
diff --git a/components/ai_chat/core/common/pref_names.h b/components/ai_chat/core/common/pref_names.h
index 5b896bb0835..36b5e82d6b7 100644
--- a/components/ai_chat/core/common/pref_names.h
+++ b/components/ai_chat/core/common/pref_names.h
@@ -117,6 +117,8 @@ inline constexpr char kObseleteBraveChatAutoGenerateQuestions[] =
inline constexpr char kBraveAIChatTabOrganizationEnabled[] =
"brave.ai_chat.tab_organization_enabled";
+inline constexpr char kBraveAIChatTabOrganizationModelKey[] =
+ "brave.ai_chat.tab_organization_model_key";
inline constexpr char kBraveAIChatUserCustomizationEnabled[] =
"brave.ai_chat.user_customization_enabled";
diff --git a/components/resources/ai_chat_prompts.grdp b/components/resources/ai_chat_prompts.grdp
index 7d4b71577da..1f94b620b02 100644
--- a/components/resources/ai_chat_prompts.grdp
+++ b/components/resources/ai_chat_prompts.grdp
@@ -269,19 +269,19 @@ Sure, here is the rewritten version of the excerpt: <response>
- Here is a list of browser topics: $1. Please return an array, delimited by "[" and "]" containing the 5 most unusual or interesting topics. Prepend each topic string with a single relevant emoji. Try to choose unrelated topics. Make sure to return only an array of strings enclosed in quotes.
+ Here is a list of browser topics: $1. Please return a valid JSON array containing the 5 most unusual or interesting topics. Prepend each topic string with a single relevant emoji. Try to choose unrelated topics. Return only a JSON array of strings using double quotes, for example: ["🔬 Science", "🎵 Music"].
- Here is a list of browser tabs with their titles and domains: $1. Please return an array, delimited by "[" and "]" of up to 5 topics that the user might be working on or researching. Ensure that the topics are diverse and unrelated. Prepend each topic string with a single relevant emoji. Make sure to return only an array of strings enclosed in quotes.
+ Here is a list of browser tabs with their titles and domains: $1. Please return a valid JSON array of up to 5 topics that the user might be working on or researching. Ensure that the topics are diverse and unrelated. Prepend each topic string with a single relevant emoji. Return only a JSON array of strings using double quotes, for example: ["🔬 Science", "🎵 Music"].
- Here is a list of browser tabs with their titles and domains: $1. Please return an array, delimited by "[" and "]" of up to 5 topics that the user might be working on or researching. Try to make the topics more detailed. Make sure to return only an array of strings enclosed in quotes.
+ Here is a list of browser tabs with their titles and domains: $1. Please return a valid JSON array of up to 5 topics that the user might be working on or researching. Try to make the topics more detailed. Return only a JSON array of strings using double quotes, for example: ["Web Development", "Machine Learning"].
- Here is a list of browser tabs with their titles and domains: $1. Please return an array, delimited by "[" and "]" of the tabIds for tabs that are a close match for the following topic: $2. Make sure to return only an array of strings enclosed in quotes.
+ Here is a list of browser tabs with their titles and domains: $1. Please return a valid JSON array of the tabIds for tabs that are a close match for the following topic: $2. Return only a JSON array of strings using double quotes, for example: ["1", "5", "12"].