commit 77b6142c6c32aaa04bae0946f7d197ef9c67aca8
parent 5f6067b46ab40e65597e759448eb613e58091920
Author: Nick Grato <ngrato@gmail.com>
Date: Mon, 6 Oct 2025 20:56:17 +0000
Bug 1990881 - basic intent ask vs search vs navigate heuristic r=Mardak,firefox-ai-ml-reviewers
building on bug 1989035 doing chat, sometimes we want it to search instead. we can do some very basic heuristic to set up an async api for it to be likely replaced by a engine/model
to start, this could reflect text of the submit button based on the typed text. eventually this might be reused for classifying quick prompts and suggestions
Differential Revision: https://phabricator.services.mozilla.com/D267500
Diffstat:
3 files changed, 84 insertions(+), 5 deletions(-)
diff --git a/browser/components/genai/SmartAssistEngine.sys.mjs b/browser/components/genai/SmartAssistEngine.sys.mjs
@@ -210,4 +210,31 @@ export const SmartAssistEngine = {
convo = [...convo, assistantToolMsg, ...toolResultMessages];
}
},
+
+ /**
+ *
+ * @param {string} prompt
+ * @returns {string} "search" | "chat"
+ */
+ async getPromptIntent(prompt) {
+ // TODO : this is mock logic to determine if the user wants to search or chat
+ // We will eventually want to use a model to determine this intent
+ const searchKeywords = [
+ "search",
+ "find",
+ "look",
+ "query",
+ "locate",
+ "explore",
+ ];
+ const formattedPrompt = prompt.toLowerCase();
+
+ const intent = searchKeywords.some(keyword =>
+ formattedPrompt.includes(keyword)
+ )
+ ? "search"
+ : "chat";
+
+ return intent;
+ },
};
diff --git a/browser/components/genai/content/smart-assist.mjs b/browser/components/genai/content/smart-assist.mjs
@@ -29,6 +29,7 @@ export class SmartAssist extends MozLitElement {
mode: { type: String }, // "tab" | "sidebar"
overrideNewTab: { type: Boolean },
showLog: { type: Boolean },
+ actionKey: { type: String }, // "chat" | "search"
};
constructor() {
@@ -45,6 +46,20 @@ export class SmartAssist extends MozLitElement {
this.overrideNewTab = Services.prefs.getBoolPref(
"browser.ml.smartAssist.overrideNewTab"
);
+ this.actionKey = "chat";
+
+ this._actions = {
+ chat: {
+ label: "Submit",
+ icon: "chrome://global/skin/icons/arrow-right.svg",
+ run: this._actionChat,
+ },
+ search: {
+ label: "Search",
+ icon: "chrome://global/skin/icons/search-glass.svg",
+ run: this._actionSearch,
+ },
+ };
}
connectedCallback() {
@@ -70,12 +85,28 @@ export class SmartAssist extends MozLitElement {
this.logState = [...this.logState, entryWithDate];
};
- _handlePromptInput = e => {
+ _handlePromptInput = async e => {
const value = e.target.value;
this.userPrompt = value;
+
+ // Determine intent based on keywords in the prompt
+ this.actionKey = await lazy.SmartAssistEngine.getPromptIntent(value);
+ };
+
+ /**
+ * Returns the current action object based on the actionKey
+ */
+
+ get inputAction() {
+ return this._actions[this.actionKey];
+ }
+
+ _actionSearch = () => {
+ // TODO: Implement search functionality
};
- _handleSubmit = async () => {
+ _actionChat = async () => {
+ console.log("this", this);
const formattedPrompt = (this.userPrompt || "").trim();
if (!formattedPrompt) {
return;
@@ -126,7 +157,7 @@ export class SmartAssist extends MozLitElement {
* Mock Functionality to open full page UX
*
* @param {boolean} enable
- * Whether or not to override the new tab page.
+ * Whether or not to override the new tab page.
*/
_applyNewTabOverride(enable) {
try {
@@ -223,12 +254,14 @@ export class SmartAssist extends MozLitElement {
@input=${e => this._handlePromptInput(e)}
></textarea>
<moz-button
+ iconSrc=${this.inputAction.icon}
id="submit-user-prompt-btn"
type="primary"
size="small"
- @click=${this._handleSubmit}
+ @click=${this.inputAction.run}
+ iconPosition="end"
>
- Submit
+ ${this.inputAction.label}
</moz-button>
<!-- Footer - New Tab Override -->
diff --git a/browser/components/genai/tests/xpcshell/test_smart_assist_engine.js b/browser/components/genai/tests/xpcshell/test_smart_assist_engine.js
@@ -177,3 +177,22 @@ add_task(async function test_fetchWithHistory_propagates_stream_error() {
sb.restore();
}
});
+
+add_task(async function test_getPromptIntent_basic() {
+ const cases = [
+ { prompt: "please search for news on firefox", expected: "search" },
+ { prompt: "Can you FIND me the docs for PageAssist?", expected: "search" }, // case-insensitive
+ { prompt: "look up the best pizza in SF", expected: "search" },
+ { prompt: "hello there, how are you?", expected: "chat" },
+ { prompt: "tell me a joke", expected: "chat" },
+ ];
+
+ for (const { prompt, expected } of cases) {
+ const intent = await SmartAssistEngine.getPromptIntent(prompt);
+ Assert.equal(
+ intent,
+ expected,
+ `getPromptIntent("${prompt}") should return "${expected}"`
+ );
+ }
+});