From 988b719eaa7abad2428490713a2d403cfc0afac4 Mon Sep 17 00:00:00 2001 From: Evan Reichard Date: Sun, 26 Jul 2026 15:36:38 -0400 Subject: [PATCH] feat(web_search): truncate results in TUI view, expand with ctrl+o Add renderResult showing a collapsed preview (count + first 3 results) until expanded via Ctrl+O. The full markdown still goes to the model via content, so only the display is affected. --- index.ts | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/index.ts b/index.ts index 626db09..62f736d 100644 --- a/index.ts +++ b/index.ts @@ -1,7 +1,12 @@ // Pi-Web Extension - Registers `web_search` and `web_fetch` tools backed by // a shared headless Firefox session. Provider config lives in // ~/.pi/pi-web/config.json (env overrides supported). -import type { ExtensionAPI } from "@mariozechner/pi-coding-agent"; +import { + keyHint, + type AgentToolResult, + type ExtensionAPI, + type Theme, +} from "@mariozechner/pi-coding-agent"; import { Text } from "@mariozechner/pi-tui"; import { Type } from "typebox"; import { ConfigError, loadConfig, resolveSettings } from "./src/config.ts"; @@ -10,6 +15,9 @@ import { searchKagi } from "./src/providers/kagi.ts"; import { searchSearxng } from "./src/providers/searxng.ts"; import { SearchError, type SearchResult } from "./src/types.ts"; +// Collapsed-view preview cap. The full list still goes to the model via `content`. +const PREVIEW_RESULTS = 3; + function formatResults(results: SearchResult[]): string { if (results.length === 0) return "(no results)"; return results @@ -17,6 +25,30 @@ function formatResults(results: SearchResult[]): string { .join("\n\n"); } +function renderSearchResult( + result: AgentToolResult, + expanded: boolean, + theme: Theme, +): Text { + const fullText = result.content[0]?.type === "text" ? result.content[0].text : ""; + const raw = (result.details as { raw?: SearchResult[] } | undefined)?.raw; + + // Expanded or unavailable details: show the full markdown the model received. + if (expanded || !raw || raw.length === 0) { + return new Text(fullText, 0, 0); + } + + let text = theme.fg("muted", `${raw.length} result(s):`); + for (const r of raw.slice(0, PREVIEW_RESULTS)) { + text += `\n${theme.fg("toolTitle", r.title)} ${theme.fg("dim", r.url)}`; + } + const more = raw.length - PREVIEW_RESULTS; + if (more > 0) { + text += `\n${theme.fg("dim", `... ${more} more (${keyHint("app.tools.expand", "to expand")})`)}`; + } + return new Text(text, 0, 0); +} + function formatFetch(r: FetchResult): string { const header = r.title && r.title.trim() @@ -55,6 +87,9 @@ export default function (pi: ExtensionAPI) { text.setText(theme.fg("toolTitle", theme.bold(`web_search "${display}"`))); return text; }, + renderResult(result, { expanded }, theme) { + return renderSearchResult(result, expanded, theme); + }, async execute(_toolCallId, params) { try { const results = await runSearch(params.query);