From 534ed85ee101556e800dfb46500ac62c4b5ebefe Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Fri, 15 May 2026 02:33:05 +0200 Subject: [PATCH] refactor(extensions): merge google-search into search-the-web Google Search was a standalone extension providing a single tool (google_search) that used Gemini's Google Search grounding feature. It had fallback logic to search-the-web providers (Tavily, Brave) when Google OAuth was unavailable. Merging it into search-the-web consolidates all web search capabilities into one extension and eliminates the tight coupling between the two. Changes: - Copied google-search tool logic into search-the-web/tool-google-search.js - Added registerGoogleSearchTool / resetGoogleSearchCache exports - Integrated into search-the-web/index.js deferred loading - Added google_search to search-the-web extension-manifest.json tools - Deleted google-search/ extension directory Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../google-search/extension-manifest.json | 12 ------------ .../extensions/google-search/package.json | 14 -------------- .../search-the-web/extension-manifest.json | 4 ++-- src/resources/extensions/search-the-web/index.js | 8 ++++++++ .../tool-google-search.js} | 13 ++++++++----- 5 files changed, 18 insertions(+), 33 deletions(-) delete mode 100644 src/resources/extensions/google-search/extension-manifest.json delete mode 100644 src/resources/extensions/google-search/package.json rename src/resources/extensions/{google-search/index.js => search-the-web/tool-google-search.js} (97%) diff --git a/src/resources/extensions/google-search/extension-manifest.json b/src/resources/extensions/google-search/extension-manifest.json deleted file mode 100644 index ab866e075..000000000 --- a/src/resources/extensions/google-search/extension-manifest.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "id": "google-search", - "name": "Google Search", - "version": "1.0.0", - "description": "Web search via Google with AI-synthesized answers and source citations", - "tier": "bundled", - "requires": { "platform": ">=2.29.0" }, - "provides": { - "tools": ["google_search"], - "hooks": ["session_start", "session_shutdown"] - } -} diff --git a/src/resources/extensions/google-search/package.json b/src/resources/extensions/google-search/package.json deleted file mode 100644 index cb5a9e2b0..000000000 --- a/src/resources/extensions/google-search/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "pi-extension-google-search", - "private": true, - "version": "1.0.0", - "type": "module", - "engines": { - "node": ">=26.1.0" - }, - "pi": { - "extensions": [ - "./index.js" - ] - } -} diff --git a/src/resources/extensions/search-the-web/extension-manifest.json b/src/resources/extensions/search-the-web/extension-manifest.json index 600480f93..be938fa79 100644 --- a/src/resources/extensions/search-the-web/extension-manifest.json +++ b/src/resources/extensions/search-the-web/extension-manifest.json @@ -2,11 +2,11 @@ "id": "search-the-web", "name": "Web Search", "version": "1.0.0", - "description": "Web search via Tavily, MiniMax, Serper, Exa, Ollama, or Brave plus page extraction", + "description": "Web search via Tavily, MiniMax, Serper, Exa, Ollama, Brave, or Google plus page extraction", "tier": "bundled", "requires": { "platform": ">=2.29.0" }, "provides": { - "tools": ["search-the-web", "fetch_page", "search_and_read", "web_search"], + "tools": ["search-the-web", "fetch_page", "search_and_read", "web_search", "google_search"], "commands": ["search-provider"], "hooks": ["session_start", "model_select", "before_provider_request"] } diff --git a/src/resources/extensions/search-the-web/index.js b/src/resources/extensions/search-the-web/index.js index 3aea3f964..fc33ed666 100644 --- a/src/resources/extensions/search-the-web/index.js +++ b/src/resources/extensions/search-the-web/index.js @@ -10,6 +10,7 @@ import { registerNativeSearchHooks } from "./native-search.js"; let toolsPromise = null; let resetSearchLoopGuardStateRef = null; +let resetGoogleSearchCacheRef = null; async function registerSearchTools(pi) { if (!toolsPromise) { toolsPromise = (async () => { @@ -17,15 +18,19 @@ async function registerSearchTools(pi) { { registerSearchTool, resetSearchLoopGuardState }, { registerFetchPageTool }, { registerLLMContextTool }, + { registerGoogleSearchTool, resetGoogleSearchCache }, ] = await Promise.all([ importExtensionModule(import.meta.url, "./tool-search.js"), importExtensionModule(import.meta.url, "./tool-fetch-page.js"), importExtensionModule(import.meta.url, "./tool-llm-context.js"), + importExtensionModule(import.meta.url, "./tool-google-search.js"), ]); resetSearchLoopGuardStateRef = resetSearchLoopGuardState; + resetGoogleSearchCacheRef = resetGoogleSearchCache; registerSearchTool(pi); registerFetchPageTool(pi); registerLLMContextTool(pi); + registerGoogleSearchTool(pi); })().catch((error) => { toolsPromise = null; throw error; @@ -42,9 +47,11 @@ export default function (pi) { }; if (ctx.hasUI) { resetLoopGuardState(); + resetGoogleSearchCacheRef?.(); void registerSearchTools(pi) .then(() => { resetLoopGuardState(); + resetGoogleSearchCacheRef?.(); }) .catch((error) => { ctx.ui.notify( @@ -56,5 +63,6 @@ export default function (pi) { } await registerSearchTools(pi); resetLoopGuardState(); + resetGoogleSearchCacheRef?.(); }); } diff --git a/src/resources/extensions/google-search/index.js b/src/resources/extensions/search-the-web/tool-google-search.js similarity index 97% rename from src/resources/extensions/google-search/index.js rename to src/resources/extensions/search-the-web/tool-google-search.js index a6f17104b..921f21381 100644 --- a/src/resources/extensions/google-search/index.js +++ b/src/resources/extensions/search-the-web/tool-google-search.js @@ -20,7 +20,7 @@ import { getBraveApiKey, getTavilyApiKey, resolveSearchProvider, -} from "../search-the-web/provider.js"; +} from "./provider.js"; /** * Build a Code Assist server through @google/gemini-cli-core. @@ -183,13 +183,11 @@ async function executeFallbackSearch(query, signal) { throw new Error("No fallback search provider available"); } -// ── In-session cache ───────────────────────────────────────────────────────── -const resultCache = new Map(); function cacheKey(query) { return query.toLowerCase().trim(); } -// ── Extension ──────────────────────────────────────────────────────────────── -export default function (pi) { +// ── Tool registration ──────────────────────────────────────────────────────── +export function registerGoogleSearchTool(pi) { pi.registerTool({ name: "google_search", label: "Google Search", @@ -411,6 +409,11 @@ export default function (pi) { } }); } +let resultCache = new Map(); +/** Reset the google_search result cache (called by search-the-web extension on session_start). */ +export function resetGoogleSearchCache() { + resultCache.clear(); +} // ── Output formatting ──────────────────────────────────────────────────────── function formatOutput(result, maxSources) { const lines = [];