import type { JSX } from "react";
import { translate } from "../../../../i18n/index";
import {
dedupeToolSectionContent,
ToolMarkdownBlock,
ToolSection,
type AgentToolRendererProps
} from "./agentToolContentShared";
import { getSearchRenderData } from "./render-data/agentToolRenderData";
export function AgentSearchContent({
call,
onLinkClick
}: AgentToolRendererProps): JSX.Element {
"use memo";
const search = getSearchRenderData(call);
const queryText = search.scope
? `${search.query ?? ""}\n\n${translate("agentHost.agentTool.details.scope")}: ${search.scope}`.trim()
: search.query;
const resultFiles = withStableOccurrenceKeys(search.files, "file");
const visibleOutput = dedupeToolSectionContent(search.output, queryText);
const outputLines = withStableOccurrenceKeys(
visibleOutput.split("\n").filter(Boolean),
"line"
);
return (
{queryText ? (
) : null}
{(search.mode === "files_with_matches" || search.mode === "list_files") &&
search.files.length > 0 ? (
{resultFiles.map(({ key, value: file, isFirst }) => (
{file}
))}
) : null}
{search.mode === "content" && visibleOutput ? (
{outputLines.map(({ key, value: line }) => (
{line}
))}
) : null}
{search.mode === "count" ? (
{search.output || "0"}
) : null}
{(search.mode === "files_with_matches" ||
search.mode === "list_files" ||
search.mode === "count") &&
search.files.length === 0 &&
!visibleOutput &&
!search.error ? (
{translate("agentHost.agentTool.details.noMatches")}
) : null}
{search.mode === "unknown" && visibleOutput ? (
) : null}
{search.error ? (
) : null}
);
}
function withStableOccurrenceKeys(
values: readonly string[],
prefix: string
): Array<{ key: string; value: string; isFirst: boolean }> {
const seen = new Map();
const keyedValues: Array<{ key: string; value: string; isFirst: boolean }> =
[];
let isFirst = true;
for (const value of values) {
const occurrence = seen.get(value) ?? 0;
seen.set(value, occurrence + 1);
keyedValues.push({
key: `${prefix}:${value}:${occurrence}`,
value,
isFirst
});
isFirst = false;
}
return keyedValues;
}