// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates // SPDX-License-Identifier: MIT import { PythonOutlined } from "@ant-design/icons"; import { parse } from "best-effort-json-parser"; import { motion } from "framer-motion"; import { LRUCache } from "lru-cache"; import { BookOpenText, Search } from "lucide-react"; import { useMemo } from "react"; import SyntaxHighlighter from "react-syntax-highlighter"; import { docco } from "react-syntax-highlighter/dist/esm/styles/hljs"; import { Skeleton } from "~/components/ui/skeleton"; import type { ToolCallRuntime } from "~/core/messages"; import { useMessage, useStore } from "~/core/store"; import { cn } from "~/lib/utils"; import { FavIcon } from "./fav-icon"; import Image from "./image"; import { LoadingAnimation } from "./loading-animation"; import { Markdown } from "./markdown"; import { RainbowText } from "./rainbow-text"; export function ResearchActivitiesBlock({ className, researchId, }: { className?: string; researchId: string; }) { const activityIds = useStore((state) => state.researchActivityIds.get(researchId), )!; const ongoing = useStore((state) => state.ongoingResearchId === researchId); return ( <> {ongoing && } ); } function ActivityMessage({ messageId }: { messageId: string }) { const message = useMessage(messageId); if (message?.agent && message.content) { if (message.agent !== "reporter" && message.agent !== "planner") { return (
{message.content}
); } } return null; } function ActivityListItem({ messageId }: { messageId: string }) { const message = useMessage(messageId); if (message) { if (!message.isStreaming && message.toolCalls?.length) { for (const toolCall of message.toolCalls) { if (toolCall.name === "web_search") { return ; } else if (toolCall.name === "crawl_tool") { return ; } else if (toolCall.name === "python_repl_tool") { return ; } } } } return null; } const __pageCache = new LRUCache({ max: 100 }); type SearchResult = | { type: "page"; title: string; url: string; content: string; } | { type: "image"; image_url: string; image_description: string; }; function WebSearchToolCall({ toolCall }: { toolCall: ToolCallRuntime }) { const searching = useMemo(() => { return toolCall.result === undefined; }, [toolCall.result]); const searchResults = useMemo(() => { let results: SearchResult[] | undefined = undefined; try { results = toolCall.result ? parse(toolCall.result) : undefined; } catch { results = undefined; } if (Array.isArray(results)) { results.forEach((result) => { if (result.type === "page") { __pageCache.set(result.url, result.title); } }); } else { results = []; } return results; }, [toolCall.result]); const pageResults = useMemo( () => searchResults?.filter((result) => result.type === "page"), [searchResults], ); const imageResults = useMemo( () => searchResults?.filter((result) => result.type === "image"), [searchResults], ); return (
Searching for  {(toolCall.args as { query: string }).query}
{pageResults && (
    {searching && [...Array(6)].map((_, i) => (
  • ))} {pageResults .filter((result) => result.type === "page") .map((searchResult, i) => ( {searchResult.title} ))} {imageResults.map((searchResult, i) => ( {searchResult.image_description} ))}
)}
); } function CrawlToolCall({ toolCall }: { toolCall: ToolCallRuntime }) { const url = useMemo( () => (toolCall.args as { url: string }).url, [toolCall.args], ); const title = useMemo(() => __pageCache.get(url), [url]); return (
Reading
); } function PythonToolCall({ toolCall }: { toolCall: ToolCallRuntime }) { const code = useMemo(() => { return (toolCall.args as { code: string }).code; }, [toolCall.args]); return (
Running Python code
{code}
); }