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>
This commit is contained in:
Mikael Hugo 2026-05-15 02:33:05 +02:00
parent f0c3eaf999
commit 534ed85ee1
5 changed files with 18 additions and 33 deletions

View file

@ -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"]
}
}

View file

@ -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"
]
}
}

View file

@ -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"]
}

View file

@ -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?.();
});
}

View file

@ -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 = [];