diff --git a/web/src/app/chat/components/research-activities-block.tsx b/web/src/app/chat/components/research-activities-block.tsx
index 3e78022..2e83196 100644
--- a/web/src/app/chat/components/research-activities-block.tsx
+++ b/web/src/app/chat/components/research-activities-block.tsx
@@ -7,7 +7,7 @@ import { LRUCache } from "lru-cache";
import { BookOpenText, FileText, PencilRuler, Search } from "lucide-react";
import { useTranslations } from "next-intl";
import { useTheme } from "next-themes";
-import { useMemo } from "react";
+import React, { useMemo } from "react";
import SyntaxHighlighter from "react-syntax-highlighter";
import { docco } from "react-syntax-highlighter/dist/esm/styles/hljs";
import { dark } from "react-syntax-highlighter/dist/esm/styles/prism";
@@ -31,6 +31,10 @@ import { useMessage, useStore } from "~/core/store";
import { parseJSON } from "~/core/utils";
import { cn } from "~/lib/utils";
+// Performance optimization constants
+const MAX_ANIMATED_ITEMS = 10; // Only animate first 10 items
+const ANIMATION_DELAY_MULTIPLIER = 0.05; // Reduced delay between animations
+
export function ResearchActivitiesBlock({
className,
researchId,
@@ -42,27 +46,36 @@ export function ResearchActivitiesBlock({
state.researchActivityIds.get(researchId),
)!;
const ongoing = useStore((state) => state.ongoingResearchId === researchId);
+
return (
<>
{activityIds.map(
- (activityId, i) =>
- i !== 0 && (
+ (activityId, i) => {
+ if (i === 0) return null;
+
+ // Performance optimization: limit animations for large lists
+ const shouldAnimate = i < MAX_ANIMATED_ITEMS;
+ const animationDelay = shouldAnimate ? Math.min(i * ANIMATION_DELAY_MULTIPLIER, 0.5) : 0;
+
+ return (
{i !== activityIds.length - 1 &&
}
- ),
+ );
+ },
)}
{ongoing && }
@@ -70,7 +83,7 @@ export function ResearchActivitiesBlock({
);
}
-function ActivityMessage({ messageId }: { messageId: string }) {
+const ActivityMessage = React.memo(({ messageId }: { messageId: string }) => {
const message = useMessage(messageId);
if (message?.agent && message.content) {
if (message.agent !== "reporter" && message.agent !== "planner") {
@@ -84,9 +97,10 @@ function ActivityMessage({ messageId }: { messageId: string }) {
}
}
return null;
-}
+});
+ActivityMessage.displayName = "ActivityMessage";
-function ActivityListItem({ messageId }: { messageId: string }) {
+const ActivityListItem = React.memo(({ messageId }: { messageId: string }) => {
const message = useMessage(messageId);
if (message) {
if (!message.isStreaming && message.toolCalls?.length) {
@@ -109,7 +123,8 @@ function ActivityListItem({ messageId }: { messageId: string }) {
}
}
return null;
-}
+});
+ActivityListItem.displayName = "ActivityListItem";
const __pageCache = new LRUCache({ max: 100 });
type SearchResult =
@@ -187,38 +202,46 @@ function WebSearchToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
))}
{pageResults
.filter((result) => result.type === "page")
- .map((searchResult, i) => (
-
-
-
- {searchResult.title}
-
-
- ))}
- {imageResults.map((searchResult, i) => (
- {
+ const shouldAnimate = i < 6; // Only animate first 6 results
+ return (
+
+
+
+ {searchResult.title}
+
+
+ );
+ })}
+ {imageResults
+ .slice(0, 10) // Limit displayed images for performance
+ .map((searchResult, i) => {
+ const shouldAnimate = i < 4; // Only animate first 4 images
+ return (
+
- ))}
+ );
+ })}
)}
@@ -263,10 +287,10 @@ function CrawlToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
@@ -320,22 +344,25 @@ function RetrieverToolCall({ toolCall }: { toolCall: ToolCallRuntime }) {
/>
))}
- {documents?.map((doc, i) => (
-
-
- {doc.title} (chunk-{i},size-{doc.content.length})
-
- ))}
+ {documents?.map((doc, i) => {
+ const shouldAnimate = i < 4; // Only animate first 4 documents
+ return (
+
+
+ {doc.title} (chunk-{i},size-{doc.content.length})
+
+ );
+ })}
)}