commit ff8afcd8c4b4fea7f1affb9ebbe38cab23caf8cb
parent 959cf1a54bfd8f05692f90a3cd7e1ff6f7722611
Author: Sandor Molnar <smolnar@mozilla.com>
Date: Thu, 11 Dec 2025 00:24:39 +0200
Revert "Bug 2003303 - Implement Title Generation r=tzhang,ai-models-reviewers,ngrato" for causing bc failures @ TitleGeneration.sys
This reverts commit 53df932c3d25e57cb8bb2eed1118b891c2aa78e3.
Diffstat:
6 files changed, 0 insertions(+), 529 deletions(-)
diff --git a/browser/components/aiwindow/models/TitleGeneration.sys.mjs b/browser/components/aiwindow/models/TitleGeneration.sys.mjs
@@ -1,75 +0,0 @@
-/**
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-import {
- openAIEngine,
- renderPrompt,
-} from "moz-src:///browser/components/aiwindow/models/Utils.sys.mjs";
-import { titleGenerationPrompt } from "moz-src:///browser/components/aiwindow/models/prompts/TitleGenerationPrompts.sys.mjs";
-
-/**
- * Generats a default title from the first four words of a message.
- *
- * @param {string} message - The user's message
- * @returns {string} The default title
- */
-function generateDefaultTitle(message) {
- if (!message || typeof message !== "string") {
- return "New Chat";
- }
-
- const words = message
- .trim()
- .split(/\s+/)
- .filter(word => !!word.length);
-
- if (words.length === 0) {
- return "New Chat";
- }
-
- const titleWords = words.slice(0, 4);
- return titleWords.join(" ") + "...";
-}
-
-/**
- * Generate a chat title based on the user's message and current tab information.
- *
- * @param {string} message - The user's message
- * @param {object} current_tab - Object containing current tab information
- * @returns {Promise<string>} The generated chat title
- */
-export async function generateChatTitle(message, current_tab) {
- try {
- // Build the OpenAI engines
- const engine = await openAIEngine.build();
-
- const tabInfo = current_tab || { url: "", title: "", description: "" };
-
- // Render the prompt with actual values
- const systemPrompt = await renderPrompt(titleGenerationPrompt, {
- current_tab: JSON.stringify(tabInfo),
- });
-
- // Prepare messages for the LLM
- const messages = [
- { role: "system", content: systemPrompt },
- { role: "user", content: message },
- ];
-
- // Call the LLM
- const response = await engine.run({ messages });
-
- // Extract the generated title from the response
- const title =
- response?.choices?.[0]?.message?.content?.trim() ||
- generateDefaultTitle(message);
-
- return title;
- } catch (error) {
- console.error("Failed to generate chat title:", error);
- return generateDefaultTitle(message);
- }
-}
diff --git a/browser/components/aiwindow/models/moz.build b/browser/components/aiwindow/models/moz.build
@@ -19,7 +19,6 @@ MOZ_SRC_FILES += [
"InsightsSchemas.sys.mjs",
"IntentClassifier.sys.mjs",
"SearchBrowsingHistory.sys.mjs",
- "TitleGeneration.sys.mjs",
"Tools.sys.mjs",
"Utils.sys.mjs",
]
diff --git a/browser/components/aiwindow/models/prompts/TitleGenerationPrompts.sys.mjs b/browser/components/aiwindow/models/prompts/TitleGenerationPrompts.sys.mjs
@@ -1,16 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-export const titleGenerationPrompt = `Generate a concise chat title using only the current user message and the current context.
-
-Rules:
-- Fewer than 6 words; reflect the main topic/intent
-- Do not end with punctuation
-- Do not write questions
-- No quotes, brackets, or emojis
-
-Inputs:
-The user is currently viewing this tab page: {current_tab}
-
-Output: Only the title.`;
diff --git a/browser/components/aiwindow/models/prompts/moz.build b/browser/components/aiwindow/models/prompts/moz.build
@@ -8,5 +8,4 @@ with Files("**"):
MOZ_SRC_FILES += [
"AssistantPrompts.sys.mjs",
"insightsPrompts.sys.mjs",
- "TitleGenerationPrompts.sys.mjs",
]
diff --git a/browser/components/aiwindow/models/tests/xpcshell/test_TitleGeneration.js b/browser/components/aiwindow/models/tests/xpcshell/test_TitleGeneration.js
@@ -1,434 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { generateChatTitle } = ChromeUtils.importESModule(
- "moz-src:///browser/components/aiwindow/models/TitleGeneration.sys.mjs"
-);
-
-const { openAIEngine } = ChromeUtils.importESModule(
- "moz-src:///browser/components/aiwindow/models/Utils.sys.mjs"
-);
-
-const { sinon } = ChromeUtils.importESModule(
- "resource://testing-common/Sinon.sys.mjs"
-);
-
-/**
- * Constants for preference keys and test values
- */
-const PREF_API_KEY = "browser.aiwindow.apiKey";
-const PREF_ENDPOINT = "browser.aiwindow.endpoint";
-const PREF_MODEL = "browser.aiwindow.model";
-
-const API_KEY = "test-api-key";
-const ENDPOINT = "https://api.test-endpoint.com/v1";
-const MODEL = "test-model";
-
-/**
- * Cleans up preferences after testing
- */
-registerCleanupFunction(() => {
- for (let pref of [PREF_API_KEY, PREF_ENDPOINT, PREF_MODEL]) {
- if (Services.prefs.prefHasUserValue(pref)) {
- Services.prefs.clearUserPref(pref);
- }
- }
-});
-
-/**
- * Test that generateChatTitle successfully generates a title
- */
-add_task(async function test_generateChatTitle_success() {
- Services.prefs.setStringPref(PREF_API_KEY, API_KEY);
- Services.prefs.setStringPref(PREF_ENDPOINT, ENDPOINT);
- Services.prefs.setStringPref(PREF_MODEL, MODEL);
-
- const sb = sinon.createSandbox();
- try {
- // Mock the engine response
- const mockResponse = {
- choices: [
- {
- message: {
- content: "Weather Forecast Query",
- },
- },
- ],
- };
-
- const fakeEngineInstance = {
- run: sb.stub().resolves(mockResponse),
- };
-
- sb.stub(openAIEngine, "_createEngine").resolves(fakeEngineInstance);
-
- const message = "What's the weather like today?";
- const currentTab = {
- url: "https://weather.example.com",
- title: "Weather Forecast",
- description: "Get current weather conditions",
- };
-
- const title = await generateChatTitle(message, currentTab);
-
- Assert.equal(
- title,
- "Weather Forecast Query",
- "Should return the generated title from the LLM"
- );
-
- Assert.ok(
- fakeEngineInstance.run.calledOnce,
- "Engine run should be called once"
- );
-
- // Verify the messages structure passed to the engine
- const callArgs = fakeEngineInstance.run.firstCall.args[0];
- Assert.ok(callArgs.messages, "Should pass messages to the engine");
- Assert.equal(
- callArgs.messages.length,
- 2,
- "Should have system and user messages"
- );
- Assert.equal(
- callArgs.messages[0].role,
- "system",
- "First message should be system"
- );
- Assert.equal(
- callArgs.messages[1].role,
- "user",
- "Second message should be user"
- );
- Assert.equal(
- callArgs.messages[1].content,
- message,
- "User message should contain the input message"
- );
-
- // Verify the system prompt contains the tab information
- const systemContent = callArgs.messages[0].content;
- Assert.ok(
- systemContent.includes(currentTab.url),
- "System prompt should include tab URL"
- );
- Assert.ok(
- systemContent.includes(currentTab.title),
- "System prompt should include tab title"
- );
- Assert.ok(
- systemContent.includes(currentTab.description),
- "System prompt should include tab description"
- );
- } finally {
- sb.restore();
- }
-});
-
-/**
- * Test that generateChatTitle handles missing tab information
- */
-add_task(async function test_generateChatTitle_no_tab_info() {
- Services.prefs.setStringPref(PREF_API_KEY, API_KEY);
- Services.prefs.setStringPref(PREF_ENDPOINT, ENDPOINT);
- Services.prefs.setStringPref(PREF_MODEL, MODEL);
-
- const sb = sinon.createSandbox();
- try {
- const mockResponse = {
- choices: [
- {
- message: {
- content: "General Question",
- },
- },
- ],
- };
-
- const fakeEngineInstance = {
- run: sb.stub().resolves(mockResponse),
- };
-
- sb.stub(openAIEngine, "_createEngine").resolves(fakeEngineInstance);
-
- const message = "Tell me about AI";
- const currentTab = null;
-
- const title = await generateChatTitle(message, currentTab);
-
- Assert.equal(
- title,
- "General Question",
- "Should return the generated title even without tab info"
- );
-
- // Verify the system prompt handles null tab
- const callArgs = fakeEngineInstance.run.firstCall.args[0];
- Assert.ok(callArgs.messages, "Should pass messages even with null tab");
- } finally {
- sb.restore();
- }
-});
-
-/**
- * Test that generateChatTitle handles empty tab fields
- */
-add_task(async function test_generateChatTitle_empty_tab_fields() {
- Services.prefs.setStringPref(PREF_API_KEY, API_KEY);
- Services.prefs.setStringPref(PREF_ENDPOINT, ENDPOINT);
- Services.prefs.setStringPref(PREF_MODEL, MODEL);
-
- const sb = sinon.createSandbox();
- try {
- const mockResponse = {
- choices: [
- {
- message: {
- content: "Untitled Chat",
- },
- },
- ],
- };
-
- const fakeEngineInstance = {
- run: sb.stub().resolves(mockResponse),
- };
-
- sb.stub(openAIEngine, "_createEngine").resolves(fakeEngineInstance);
-
- const message = "Hello";
- const currentTab = {
- url: "",
- title: "",
- description: "",
- };
-
- const title = await generateChatTitle(message, currentTab);
-
- Assert.equal(title, "Untitled Chat", "Should handle empty tab fields");
-
- // Verify the system prompt includes the empty tab object
- const callArgs = fakeEngineInstance.run.firstCall.args[0];
- Assert.ok(
- callArgs.messages,
- "Should pass messages even with empty tab fields"
- );
- } finally {
- sb.restore();
- }
-});
-
-/**
- * Test that generateChatTitle handles engine errors gracefully
- */
-add_task(async function test_generateChatTitle_engine_error() {
- Services.prefs.setStringPref(PREF_API_KEY, API_KEY);
- Services.prefs.setStringPref(PREF_ENDPOINT, ENDPOINT);
- Services.prefs.setStringPref(PREF_MODEL, MODEL);
-
- const sb = sinon.createSandbox();
- try {
- const fakeEngineInstance = {
- run: sb.stub().rejects(new Error("Engine failed")),
- };
-
- sb.stub(openAIEngine, "_createEngine").resolves(fakeEngineInstance);
-
- const message = "Test message for error handling";
- const currentTab = {
- url: "https://example.com",
- title: "Example",
- description: "Test",
- };
-
- const title = await generateChatTitle(message, currentTab);
-
- Assert.equal(
- title,
- "Test message for error...",
- "Should return first four words when engine fails"
- );
- } finally {
- sb.restore();
- }
-});
-
-/**
- * Test that generateChatTitle handles malformed engine responses
- */
-add_task(async function test_generateChatTitle_malformed_response() {
- Services.prefs.setStringPref(PREF_API_KEY, API_KEY);
- Services.prefs.setStringPref(PREF_ENDPOINT, ENDPOINT);
- Services.prefs.setStringPref(PREF_MODEL, MODEL);
-
- const sb = sinon.createSandbox();
- try {
- // Test with missing choices
- const mockResponse1 = {};
- let fakeEngineInstance = {
- run: sb.stub().resolves(mockResponse1),
- };
- sb.stub(openAIEngine, "_createEngine").resolves(fakeEngineInstance);
-
- let title = await generateChatTitle("test message one two", null);
- Assert.equal(
- title,
- "test message one two...",
- "Should return first four words for missing choices"
- );
-
- // Test with empty choices array
- sb.restore();
- const sb2 = sinon.createSandbox();
- const mockResponse2 = { choices: [] };
- fakeEngineInstance = {
- run: sb2.stub().resolves(mockResponse2),
- };
- sb2.stub(openAIEngine, "_createEngine").resolves(fakeEngineInstance);
-
- title = await generateChatTitle("another test message here", null);
- Assert.equal(
- title,
- "another test message here...",
- "Should return first four words for empty choices"
- );
-
- // Test with null content
- sb2.restore();
- const sb3 = sinon.createSandbox();
- const mockResponse3 = {
- choices: [{ message: { content: null } }],
- };
- fakeEngineInstance = {
- run: sb3.stub().resolves(mockResponse3),
- };
- sb3.stub(openAIEngine, "_createEngine").resolves(fakeEngineInstance);
-
- title = await generateChatTitle("short test here", null);
- Assert.equal(
- title,
- "short test here...",
- "Should return first four words for null content"
- );
-
- sb3.restore();
- } finally {
- sb.restore();
- }
-});
-
-/**
- * Test that generateChatTitle trims whitespace from response
- */
-add_task(async function test_generateChatTitle_trim_whitespace() {
- Services.prefs.setStringPref(PREF_API_KEY, API_KEY);
- Services.prefs.setStringPref(PREF_ENDPOINT, ENDPOINT);
- Services.prefs.setStringPref(PREF_MODEL, MODEL);
-
- const sb = sinon.createSandbox();
- try {
- const mockResponse = {
- choices: [
- {
- message: {
- content: " Title With Spaces \n\n",
- },
- },
- ],
- };
-
- const fakeEngineInstance = {
- run: sb.stub().resolves(mockResponse),
- };
-
- sb.stub(openAIEngine, "_createEngine").resolves(fakeEngineInstance);
-
- const title = await generateChatTitle("test", null);
-
- Assert.equal(
- title,
- "Title With Spaces",
- "Should trim whitespace from generated title"
- );
- } finally {
- sb.restore();
- }
-});
-
-/**
- * Test default title generation with fewer than four words
- */
-add_task(async function test_generateChatTitle_short_message() {
- Services.prefs.setStringPref(PREF_API_KEY, API_KEY);
- Services.prefs.setStringPref(PREF_ENDPOINT, ENDPOINT);
- Services.prefs.setStringPref(PREF_MODEL, MODEL);
-
- const sb = sinon.createSandbox();
- try {
- const fakeEngineInstance = {
- run: sb.stub().rejects(new Error("Engine failed")),
- };
-
- sb.stub(openAIEngine, "_createEngine").resolves(fakeEngineInstance);
-
- // Test with three words
- let title = await generateChatTitle("Hello there friend", null);
- Assert.equal(
- title,
- "Hello there friend...",
- "Should return three words with ellipsis"
- );
-
- // Test with one word
- title = await generateChatTitle("Hello", null);
- Assert.equal(title, "Hello...", "Should return one word with ellipsis");
-
- // Test with empty message
- title = await generateChatTitle("", null);
- Assert.equal(
- title,
- "New Chat",
- "Should return 'New Chat' for empty message"
- );
-
- // Test with whitespace only
- title = await generateChatTitle(" ", null);
- Assert.equal(
- title,
- "New Chat",
- "Should return 'New Chat' for whitespace-only message"
- );
- } finally {
- sb.restore();
- }
-});
-
-/**
- * Test default title generation with more than four words
- */
-add_task(async function test_generateChatTitle_long_message() {
- Services.prefs.setStringPref(PREF_API_KEY, API_KEY);
- Services.prefs.setStringPref(PREF_ENDPOINT, ENDPOINT);
- Services.prefs.setStringPref(PREF_MODEL, MODEL);
-
- const sb = sinon.createSandbox();
- try {
- const fakeEngineInstance = {
- run: sb.stub().rejects(new Error("Engine failed")),
- };
-
- sb.stub(openAIEngine, "_createEngine").resolves(fakeEngineInstance);
-
- const message = "This is a very long message with many words";
- const title = await generateChatTitle(message, null);
-
- Assert.equal(
- title,
- "This is a very...",
- "Should return only first four words with ellipsis"
- );
- } finally {
- sb.restore();
- }
-});
diff --git a/browser/components/aiwindow/models/tests/xpcshell/xpcshell.toml b/browser/components/aiwindow/models/tests/xpcshell/xpcshell.toml
@@ -18,8 +18,6 @@ support-files = []
["test_SearchBrowsingHistory.js"]
-["test_TitleGeneration.js"]
-
["test_Tools_GetOpenTabs.js"]
["test_Tools_SearchBrowsingHistory.js"]