commit dc4e9d14937fb0fff9c2cc427826df18002bd4fb
parent 8e2ce9cb378d9cf2dd174e85dd69b8b149fbf0e6
Author: Molly Shillabeer <mshillabeer@mozilla.com>
Date: Tue, 30 Dec 2025 21:20:20 +0000
Bug 2007938 - Add check for history enablement for New Tab conversation starters r=tzhang,ai-models-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D277657
Diffstat:
2 files changed, 196 insertions(+), 75 deletions(-)
diff --git a/browser/components/aiwindow/models/ConversationSuggestions.sys.mjs b/browser/components/aiwindow/models/ConversationSuggestions.sys.mjs
@@ -114,9 +114,9 @@ export const NewTabStarterGenerator = {
// TODO: discuss with design about updating phrasing to "pages" instead of "tabs"
browsingPrompts: [
- { text: "Find tabs in history", minTabs: 0 },
- { text: "Summarize tabs", minTabs: 1 },
- { text: "Compare tabs", minTabs: 2 },
+ { text: "Find tabs in history", minTabs: 0, needsHistory: true },
+ { text: "Summarize tabs", minTabs: 1, needsHistory: false },
+ { text: "Compare tabs", minTabs: 2, needsHistory: false },
],
getRandom(arr) {
@@ -124,27 +124,41 @@ export const NewTabStarterGenerator = {
},
/**
- * Generate conversation starter prompts based on number of open tabs
+ * Generate conversation starter prompts based on number of open tabs and browsing history prefs.
+ * "places.history.enabled" covers "Remember browsing and download history" while
+ * "browser.privatebrowsing.autostart" covers "Always use private mode" and "Never remember history".
+ * We need to check both prefs to cover all cases where history can be disabled.
*
* @param {number} tabCount - number of open tabs
* @returns {Promise<Array>} Array of {text, type} suggestion objects
*/
async getPrompts(tabCount) {
+ const historyEnabled = Services.prefs.getBoolPref("places.history.enabled");
+ const privateBrowsing = Services.prefs.getBoolPref(
+ "browser.privatebrowsing.autostart"
+ );
const validBrowsingPrompts = this.browsingPrompts.filter(
- p => tabCount >= p.minTabs
+ p =>
+ tabCount >= p.minTabs &&
+ (!p.needsHistory || (historyEnabled && !privateBrowsing))
);
const writingPrompt = this.getRandom(this.writingPrompts);
const planningPrompt = this.getRandom(this.planningPrompts);
const browsingPrompt = validBrowsingPrompts.length
? this.getRandom(validBrowsingPrompts)
- : this.browsingPrompts[0];
+ : null;
- return [
+ const prompts = [
{ text: writingPrompt, type: "chat" },
{ text: planningPrompt, type: "chat" },
- { text: browsingPrompt.text, type: "chat" },
];
+
+ if (browsingPrompt) {
+ prompts.push({ text: browsingPrompt.text, type: "chat" });
+ }
+
+ return prompts;
},
};
diff --git a/browser/components/aiwindow/models/tests/xpcshell/test_ConversationSuggestions.js b/browser/components/aiwindow/models/tests/xpcshell/test_ConversationSuggestions.js
@@ -35,6 +35,8 @@ const { sinon } = ChromeUtils.importESModule(
const PREF_API_KEY = "browser.aiwindow.apiKey";
const PREF_ENDPOINT = "browser.aiwindow.endpoint";
const PREF_MODEL = "browser.aiwindow.model";
+const PREF_HISTORY_ENABLED = "places.history.enabled";
+const PREF_PRIVATE_BROWSING = "browser.privatebrowsing.autostart";
const API_KEY = "test-api-key";
const ENDPOINT = "https://api.test-endpoint.com/v1";
@@ -44,7 +46,13 @@ const MODEL = "test-model";
* Cleans up preferences after testing
*/
registerCleanupFunction(() => {
- for (let pref of [PREF_API_KEY, PREF_ENDPOINT, PREF_MODEL]) {
+ for (let pref of [
+ PREF_API_KEY,
+ PREF_ENDPOINT,
+ PREF_MODEL,
+ PREF_HISTORY_ENABLED,
+ PREF_PRIVATE_BROWSING,
+ ]) {
if (Services.prefs.prefHasUserValue(pref)) {
Services.prefs.clearUserPref(pref);
}
@@ -257,78 +265,177 @@ add_task(function test_cleanInferenceOutput() {
/**
* Tests for createNewTabPromptGenerator generating prompts based on tab count
*/
-add_task(async function test_createNewTabPromptGenerator() {
- const sb = sinon.createSandbox();
- const writingPrompts = [
- "Write a first draft",
- "Improve writing",
- "Proofread a message",
- ];
+add_task(
+ async function test_createNewTabPromptGenerator_with_history_enabled() {
+ const sb = sinon.createSandbox();
+ const writingPrompts = [
+ "Write a first draft",
+ "Improve writing",
+ "Proofread a message",
+ ];
- const planningPrompts = [
- "Simplify a topic",
- "Brainstorm ideas",
- "Help make a plan",
- ];
- try {
- const cases = [
- {
- input: { tabCount: -1 },
- expectedBrowsing: ["Find tabs in history"],
- },
- {
- input: { tabCount: 0 },
- expectedBrowsing: ["Find tabs in history"],
- },
- {
- input: { tabCount: 1 },
- expectedBrowsing: ["Find tabs in history", "Summarize tabs"],
- },
- {
- input: { tabCount: 2 },
- expectedBrowsing: [
- "Find tabs in history",
- "Summarize tabs",
- "Compare tabs",
- ],
- },
- {
- input: { tabCount: 3 },
- expectedBrowsing: [
- "Find tabs in history",
- "Summarize tabs",
- "Compare tabs",
- ],
- },
+ const planningPrompts = [
+ "Simplify a topic",
+ "Brainstorm ideas",
+ "Help make a plan",
];
- const promptGenerator = NewTabStarterGenerator;
- for (const { input, expectedBrowsing } of cases) {
- const results = await promptGenerator.getPrompts(input.tabCount);
- Assert.equal(results.length, 3, "Should return 3 suggestions");
- for (const result of results) {
- Assert.equal(
- result.type,
- "chat",
- "Each result should have type 'chat'"
+ try {
+ const cases = [
+ {
+ input: { tabCount: -1 },
+ expectedBrowsing: [],
+ },
+ {
+ input: { tabCount: 0 },
+ expectedBrowsing: ["Find tabs in history"],
+ },
+ {
+ input: { tabCount: 1 },
+ expectedBrowsing: ["Find tabs in history", "Summarize tabs"],
+ },
+ {
+ input: { tabCount: 2 },
+ expectedBrowsing: [
+ "Find tabs in history",
+ "Summarize tabs",
+ "Compare tabs",
+ ],
+ },
+ {
+ input: { tabCount: 3 },
+ expectedBrowsing: [
+ "Find tabs in history",
+ "Summarize tabs",
+ "Compare tabs",
+ ],
+ },
+ ];
+ const promptGenerator = NewTabStarterGenerator;
+ for (const { input, expectedBrowsing } of cases) {
+ const results = await promptGenerator.getPrompts(input.tabCount);
+ if (input.tabCount <= -1) {
+ Assert.equal(results.length, 2, "Should return 2 suggestions");
+ } else {
+ Assert.equal(results.length, 3, "Should return 3 suggestions");
+ }
+ for (const result of results) {
+ Assert.equal(
+ result.type,
+ "chat",
+ "Each result should have type 'chat'"
+ );
+ }
+ Assert.ok(
+ writingPrompts.includes(results[0].text),
+ "Results should include a valid writing prompt"
+ );
+ Assert.ok(
+ planningPrompts.includes(results[1].text),
+ "Results should include a valid planning prompt"
);
+ if (results[2]) {
+ Assert.ok(
+ expectedBrowsing.includes(results[2].text),
+ "Results should include a valid browsing prompt"
+ );
+ }
}
- Assert.ok(
- writingPrompts.includes(results[0].text),
- "Results should include a valid writing prompt"
- );
- Assert.ok(
- planningPrompts.includes(results[1].text),
- "Results should include a valid planning prompt"
- );
- Assert.ok(
- expectedBrowsing.includes(results[2].text),
- "Results should include a valid browsing prompt"
- );
+ } finally {
+ sb.restore();
}
- } finally {
- sb.restore();
}
-});
+);
+
+/**
+ * Tests for createNewTabPromptGenerator generating prompts based on tab count, with history disabled
+ */
+add_task(
+ async function test_createNewTabPromptGenerator_with_history_disabled() {
+ const sb = sinon.createSandbox();
+ const writingPrompts = [
+ "Write a first draft",
+ "Improve writing",
+ "Proofread a message",
+ ];
+
+ const planningPrompts = [
+ "Simplify a topic",
+ "Brainstorm ideas",
+ "Help make a plan",
+ ];
+ try {
+ const cases = [
+ {
+ input: { tabCount: -1 },
+ expectedBrowsing: [],
+ },
+ {
+ input: { tabCount: 0 },
+ expectedBrowsing: [],
+ },
+ {
+ input: { tabCount: 1 },
+ expectedBrowsing: ["Summarize tabs"],
+ },
+ {
+ input: { tabCount: 2 },
+ expectedBrowsing: ["Summarize tabs", "Compare tabs"],
+ },
+ {
+ input: { tabCount: 3 },
+ expectedBrowsing: ["Summarize tabs", "Compare tabs"],
+ },
+ ];
+ for (const pref of [
+ [{ key: PREF_HISTORY_ENABLED, value: false }],
+ [{ key: PREF_PRIVATE_BROWSING, value: true }],
+ [
+ { key: PREF_HISTORY_ENABLED, value: false },
+ { key: PREF_PRIVATE_BROWSING, value: true },
+ ],
+ ]) {
+ for (const p of pref) {
+ Services.prefs.setBoolPref(p.key, p.value);
+ }
+ const promptGenerator = NewTabStarterGenerator;
+ for (const { input, expectedBrowsing } of cases) {
+ const results = await promptGenerator.getPrompts(input.tabCount);
+ if (input.tabCount <= 0) {
+ Assert.equal(results.length, 2, "Should return 2 suggestions");
+ } else {
+ Assert.equal(results.length, 3, "Should return 3 suggestions");
+ }
+ for (const result of results) {
+ Assert.equal(
+ result.type,
+ "chat",
+ "Each result should have type 'chat'"
+ );
+ }
+ Assert.ok(
+ writingPrompts.includes(results[0].text),
+ "Results should include a valid writing prompt"
+ );
+ Assert.ok(
+ planningPrompts.includes(results[1].text),
+ "Results should include a valid planning prompt"
+ );
+ if (results[2]) {
+ Assert.ok(
+ expectedBrowsing.includes(results[2].text),
+ "Results should include a valid browsing prompt"
+ );
+ }
+ }
+ for (const p of pref) {
+ Services.prefs.clearUserPref(p.key);
+ }
+ }
+ } finally {
+ sb.restore();
+ }
+ }
+);
/**
* Tests for generateConversationStartersSidebar successfully generating suggestions