From e7457983a14d0d290b2fb8b6858881749035f43b Mon Sep 17 00:00:00 2001 From: majdyz Date: Wed, 22 Apr 2026 00:11:46 +0700 Subject: [PATCH] feat(frontend/copilot): align web_search UI with native WebSearch rendering - Map ``web_search`` to the ``web`` tool category so the MCP copilot tool shares the globe icon + accordion layout with the SDK's native ``WebSearch``. - Render the structured ``results`` array (title / url / snippet / page_age) as clickable citation list instead of dumping JSON. Falls back to the existing ``content`` / MCP text / raw JSON path for the pre-existing ``web_fetch`` + native ``WebSearch`` shapes. --- .../copilot/tools/GenericTool/GenericTool.tsx | 61 ++++++++++++++++--- .../copilot/tools/GenericTool/helpers.ts | 1 + 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/autogpt_platform/frontend/src/app/(platform)/copilot/tools/GenericTool/GenericTool.tsx b/autogpt_platform/frontend/src/app/(platform)/copilot/tools/GenericTool/GenericTool.tsx index 995c18df05..5ea634a69a 100644 --- a/autogpt_platform/frontend/src/app/(platform)/copilot/tools/GenericTool/GenericTool.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/copilot/tools/GenericTool/GenericTool.tsx @@ -305,15 +305,60 @@ function getWebAccordionData( string, unknown >; - const url = - getStringField(inp as Record, "url", "query") ?? - "Web content"; + const query = getStringField(inp, "query"); + const url = getStringField(inp, "url") ?? query ?? "Web content"; + + const results = Array.isArray(output.results) + ? (output.results as Array>) + : null; + + if (results) { + return { + title: `${results.length} search result${results.length === 1 ? "" : "s"}`, + description: query ? truncate(query, 80) : undefined, + content: ( +
+ {results.map((r, i) => { + const title = getStringField(r, "title") ?? "(untitled)"; + const href = getStringField(r, "url") ?? ""; + const snippet = getStringField(r, "snippet"); + const pageAge = getStringField(r, "page_age"); + return ( +
+ {href ? ( + + {title} + + ) : ( + {title} + )} + {href && ( +
+ {truncate(href, 100)} +
+ )} + {snippet && ( +

{snippet}

+ )} + {pageAge && ( +
{pageAge}
+ )} +
+ ); + })} +
+ ), + }; + } - // Try direct string fields first, then MCP content blocks, then raw JSON let content = getStringField(output, "content", "text", "_raw"); if (!content) content = extractMcpText(output); if (!content) { - // Fallback: render the raw JSON so the accordion isn't empty try { const raw = JSON.stringify(output, null, 2); if (raw !== "{}") content = raw; @@ -327,11 +372,7 @@ function getWebAccordionData( const message = getStringField(output, "message"); return { - title: statusCode - ? `Response (${statusCode})` - : url - ? "Web fetch" - : "Search results", + title: statusCode ? `Response (${statusCode})` : "Web fetch", description: truncate(url, 80), content: content ? ( {content} diff --git a/autogpt_platform/frontend/src/app/(platform)/copilot/tools/GenericTool/helpers.ts b/autogpt_platform/frontend/src/app/(platform)/copilot/tools/GenericTool/helpers.ts index f8da6fbc2f..345a2a7ca5 100644 --- a/autogpt_platform/frontend/src/app/(platform)/copilot/tools/GenericTool/helpers.ts +++ b/autogpt_platform/frontend/src/app/(platform)/copilot/tools/GenericTool/helpers.ts @@ -60,6 +60,7 @@ export function getToolCategory(toolName: string): ToolCategory { case "bash_exec": return "bash"; case "web_fetch": + case "web_search": case "WebSearch": case "WebFetch": return "web";