From 9d43525020ee5de61efc8b8a939ba3e357a508ca Mon Sep 17 00:00:00 2001 From: Darnell Andries Date: Fri, 20 Mar 2026 11:05:11 -0700 Subject: [PATCH] Add NTP widget answer to Leo entry point metrics (#34592) --- .../context/ai_chat_context.tsx | 5 ++++- .../ai_chat/core/browser/ai_chat_metrics.cc | 13 +++++++++++-- components/ai_chat/core/browser/ai_chat_metrics.h | 4 +++- .../core/browser/ai_chat_metrics_unittest.cc | 15 +++++++++++---- .../ai_chat/core/common/mojom/ai_chat.mojom | 3 +++ .../ai_chat/resources/page/api/mock_interfaces.ts | 1 + .../resources/page/state/conversation_context.tsx | 8 ++++++-- 7 files changed, 39 insertions(+), 10 deletions(-) diff --git a/browser/resources/brave_new_tab_page_refresh/context/ai_chat_context.tsx b/browser/resources/brave_new_tab_page_refresh/context/ai_chat_context.tsx index 45666a6c2f6..a07b07a86a9 100644 --- a/browser/resources/brave_new_tab_page_refresh/context/ai_chat_context.tsx +++ b/browser/resources/brave_new_tab_page_refresh/context/ai_chat_context.tsx @@ -38,7 +38,10 @@ export default function AIChatContextsProvider(props: { conversationEntriesComponent={() => <>} > - + {props.children} diff --git a/components/ai_chat/core/browser/ai_chat_metrics.cc b/components/ai_chat/core/browser/ai_chat_metrics.cc index feb9deeff10..043d389ad4f 100644 --- a/components/ai_chat/core/browser/ai_chat_metrics.cc +++ b/components/ai_chat/core/browser/ai_chat_metrics.cc @@ -73,6 +73,7 @@ constexpr char kToolbarButtonEntryPointKey[] = "toolbar_button"; constexpr char kMenuItemEntryPointKey[] = "menu_item"; constexpr char kOmniboxCommandEntryPointKey[] = "omnibox_command"; constexpr char kBraveSearchEntryPointKey[] = "brave_search"; +constexpr char kNTPWidgetEntryPointKey[] = "ntp_widget"; constexpr auto kContextMenuActionKeys = base::MakeFixedFlatMap( @@ -93,7 +94,8 @@ constexpr auto kEntryPointKeys = {EntryPoint::kToolbarButton, kToolbarButtonEntryPointKey}, {EntryPoint::kMenuItem, kMenuItemEntryPointKey}, {EntryPoint::kOmniboxCommand, kOmniboxCommandEntryPointKey}, - {EntryPoint::kBraveSearch, kBraveSearchEntryPointKey}}); + {EntryPoint::kBraveSearch, kBraveSearchEntryPointKey}, + {EntryPoint::kNTPWidget, kNTPWidgetEntryPointKey}}); #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) @@ -324,7 +326,8 @@ void AIChatMetrics::RecordReset() { UMA_HISTOGRAM_EXACT_LINEAR(kEnabledHistogramName, std::numeric_limits::max() - 1, 3); UMA_HISTOGRAM_EXACT_LINEAR(kAcquisitionSourceHistogramName, - std::numeric_limits::max() - 1, 7); + std::numeric_limits::max() - 1, + static_cast(EntryPoint::kMaxValue) + 1); } void AIChatMetrics::OnPremiumStatusUpdated(bool is_enabled, @@ -418,6 +421,12 @@ void AIChatMetrics::OnSendingPromptWithFullPage() { prompted_via_full_page_ = true; } +void AIChatMetrics::OnSendingPromptWithNTP() { +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) + HandleOpenViaEntryPoint(EntryPoint::kNTPWidget); +#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +} + void AIChatMetrics::OnQuickActionStatusChange(bool is_enabled) { prompted_via_quick_action_ = is_enabled; } diff --git a/components/ai_chat/core/browser/ai_chat_metrics.h b/components/ai_chat/core/browser/ai_chat_metrics.h index e3f37967fa6..a9c1188b46a 100644 --- a/components/ai_chat/core/browser/ai_chat_metrics.h +++ b/components/ai_chat/core/browser/ai_chat_metrics.h @@ -97,7 +97,8 @@ enum class EntryPoint { kMenuItem = 4, kOmniboxCommand = 5, kBraveSearch = 6, - kMaxValue = kBraveSearch + kNTPWidget = 7, + kMaxValue = kNTPWidget }; enum class ContextMenuAction { @@ -182,6 +183,7 @@ class AIChatMetrics : public mojom::Metrics, // Metrics: void OnSendingPromptWithFullPage() override; + void OnSendingPromptWithNTP() override; void OnQuickActionStatusChange(bool is_enabled) override; void RecordSkillClick(const std::string& skill_id) override; diff --git a/components/ai_chat/core/browser/ai_chat_metrics_unittest.cc b/components/ai_chat/core/browser/ai_chat_metrics_unittest.cc index b7650c979b8..ac599111c5b 100644 --- a/components/ai_chat/core/browser/ai_chat_metrics_unittest.cc +++ b/components/ai_chat/core/browser/ai_chat_metrics_unittest.cc @@ -281,9 +281,10 @@ TEST_F(AIChatMetricsUnitTest, AcquisitionSource) { ai_chat_metrics_->RecordOmniboxOpen(); histogram_tester_.ExpectUniqueSample(kAcquisitionSourceHistogramName, 1, 1); + ai_chat_metrics_->OnSendingPromptWithNTP(); ai_chat_metrics_->RecordEnabled(true, true, GetPremiumCallback()); histogram_tester_.ExpectTotalCount(kAcquisitionSourceHistogramName, 2); - histogram_tester_.ExpectBucketCount(kAcquisitionSourceHistogramName, 0, 1); + histogram_tester_.ExpectBucketCount(kAcquisitionSourceHistogramName, 7, 1); } TEST_F(AIChatMetricsUnitTest, OmniboxOpens) { @@ -421,11 +422,17 @@ TEST_F(AIChatMetricsUnitTest, MostUsedEntryPoint) { kMostUsedEntryPointHistogramName, static_cast(EntryPoint::kBraveSearch), 1); - task_environment_.FastForwardBy(base::Days(7)); - histogram_tester_.ExpectTotalCount(kMostUsedEntryPointHistogramName, 14); + for (size_t i = 0; i < 5; i++) { + ai_chat_metrics_->OnSendingPromptWithNTP(); + } + + histogram_tester_.ExpectBucketCount(kMostUsedEntryPointHistogramName, 7, 1); task_environment_.FastForwardBy(base::Days(7)); - histogram_tester_.ExpectTotalCount(kMostUsedEntryPointHistogramName, 14); + histogram_tester_.ExpectTotalCount(kMostUsedEntryPointHistogramName, 19); + + task_environment_.FastForwardBy(base::Days(7)); + histogram_tester_.ExpectTotalCount(kMostUsedEntryPointHistogramName, 19); } #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) diff --git a/components/ai_chat/core/common/mojom/ai_chat.mojom b/components/ai_chat/core/common/mojom/ai_chat.mojom index 9da7a46e45b..8af147e4960 100644 --- a/components/ai_chat/core/common/mojom/ai_chat.mojom +++ b/components/ai_chat/core/common/mojom/ai_chat.mojom @@ -435,6 +435,9 @@ interface Metrics { // Notify metrics service that a full page prompt is being sent OnSendingPromptWithFullPage(); + // Notify metrics service that a prompt is being sent from the NTP widget + OnSendingPromptWithNTP(); + // Notify metrics service if a quick action is being used OnQuickActionStatusChange(bool is_enabled); diff --git a/components/ai_chat/resources/page/api/mock_interfaces.ts b/components/ai_chat/resources/page/api/mock_interfaces.ts index 86321c295ae..14994be2726 100644 --- a/components/ai_chat/resources/page/api/mock_interfaces.ts +++ b/components/ai_chat/resources/page/api/mock_interfaces.ts @@ -261,6 +261,7 @@ export function createMockMetrics( overrides: Partial = {}, ): Closable { return makeCloseable({ + onSendingPromptWithNTP: () => {}, onQuickActionStatusChange: () => {}, onSendingPromptWithFullPage: () => {}, recordSkillClick: () => {}, diff --git a/components/ai_chat/resources/page/state/conversation_context.tsx b/components/ai_chat/resources/page/state/conversation_context.tsx index c56286242b5..51ecf4cab23 100644 --- a/components/ai_chat/resources/page/state/conversation_context.tsx +++ b/components/ai_chat/resources/page/state/conversation_context.tsx @@ -55,7 +55,9 @@ export function useCharCountInfo(inputText: string) { // Each instance of ConversationContext should be provided with an API interface // connected to the relevant API endpoints. -export type ConversationContextProps = SelectedChatDetails +export type ConversationContextProps = SelectedChatDetails & { + isNTPWidget?: boolean +} // // Given the provided conversation API connection, provides neccessary @@ -281,7 +283,9 @@ export function useProvideConversationContext(props: ConversationContextProps) { aiChat.dismissStorageNotice() } - if (aiChat.isStandalone) { + if (props.isNTPWidget) { + aiChat.api.metrics.onSendingPromptWithNTP() + } else if (aiChat.isStandalone) { aiChat.api.metrics.onSendingPromptWithFullPage() }